上一章我们已经分析了Spring实例化bean的步骤,以及对实例化方式的解析,本章分析Spring使用无参构造函数实例化bean的过程。
在分析之前先来了解一下Spring实例化bean的策略
- JDK的反射机制
- CGLIB动态代理
对于反射机制,如果拿到其构造函数,参数等相关信息,就可以通过反射直接创建其实例,但是为什么Spring提供了两种实例化的方式呢,答案就是我们之前分析的方法注入。14–Spring lookup-method注入和replace-method注入(二),如果当前bean是通过lookup-method或者replace-method话,那么这时就需要用到CGLIB进行动态代理,以便在创建代理的同时将动态方法织入到类中。
Spring中的实例化策略通过InstantiationStrategy类来定义,它有两个实现类,CglibSubclassingInstantiationStrategy和SimpleInstantiationStrategy,其中前者继承了后者。对于这两个类有什么区别呢?
描述 | CglibSubclassingInstantiationStrategy | SimpleInstantiationStrategy |
---|---|---|
是否Spring默认实例化策略 | 是 | 否 |
是否支持方法注入实例化 | 是 | 否 |
是否反射实例化 | 是 | 是 |
接着上一章的分析,我们来看源码,打开AbstractAutowireCapableBeanFactory类的instantiateBean方法
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
// 如果权限管理器不为空,需要校验
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
getInstantiationStrategy().instantiate(mbd, beanName, parent),
getAccessControlContext());
}
else {
// 获取实例化策略并实例化bean
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}
可以看到实例化bean的方法为instantiate,进入到SimpleInstantiationStrategy类的instantiate方法中,继续查看:
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// 如果没有使用方法覆盖(replace-method或lookup-method注入),则直接使用反射创建bean的实例
// Don't override the class with CGLIB if no overrides.
if (!bd.hasMethodOverrides()) {
Constructor<?> constructorToUse;
synchronized (bd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
final Class<?> clazz = bd.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
constructorToUse = AccessController.doPrivileged((PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
}
else {
constructorToUse = clazz.getDeclaredConstructor();
}
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// 否则必须使用CGLIB实例化策略
// Must generate CGLIB subclass.
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
在该方法中,Spring对使用JDK的反射实例化还是CGLIB实例化进行了判断。如果没有方法覆盖(replace-method或lookup-method注入)则使用JDK的反射机制进行实例化,如果有的话,则使用CGLIB动态代理进行实例化。
具体的实例化代码这里就不分析了,大家可以使用一个普通的bean和使用了replace-method或lookup-method注入的bean进行debug。参考14–Spring lookup-method注入和replace-method注入(二)
Spring默认构造函数的实例化还是比较简单的,下一篇我们分析对构造函数参数的解析,就比较复杂了!