- 回顾
- 使用构造方法构建Bean
- instantiate方法
- 实例化策略
- 没有覆盖方法的实例化
- 拥有覆盖方法的实例化
- 总结一下
前面已经看了整个Bean的加载过程了,并且在上一章已经看到了,Spring如何对Bean的构造方法进行筛选,Spring将筛选构造方法和使用构造方法创建Bean都交由了ConstructResolver负责
下面就看下,Spring如何利用构造方法来创建Bean的
使用构造方法构建Bean先看一下ConstrutResolver找到了构造方法是如何实例Bean的
可以看到,代码为
bw.setBeanInstance(instantiate(beanName,mbd,constructorToUser,argsToUse))
逻辑也很简单,使用instantiate方法实例Bean,然后装配进beanWrapper中
instantiate方法
源码如下
private Object instantiate(
String beanName, RootBeanDefinition mbd, Constructor> constructorToUse, Object[] argsToUse) {
try {
//从beanFactory获取实例化策略
InstantiationStrategy strategy = this.beanFactory.getInstantiationStrategy();
//判断有没有开安全管理配置器
if (System.getSecurityManager() != null) {
return AccessController.doPrivileged((PrivilegedAction
逻辑如下
- 根据beanFactory去获取实例化策略
- 使用实例化策略去进行创建bean
实例化过程需要使用实例化策略,那么实例化策略是用来做什么的呢?
经过前面一系列的步骤,我们已经得到了足以实例化的所有信息,完全可以使用最简单的反射方法来直接反射来构造实例对象,但是Spring并不是直接这么做,因为这还涉及一个动态代理问题,而是让策略去做,也就是使用策略模式去进行实例化Bean
可以看到,这个InstantiationStrategy是一个接口,并且有两个实现类
- SimpleInstantiationStrategy:简单的实例化策略
- CglibSubclassingInstantiationStrategy:扩展了SimpleInstantiationStrategy,默认的策略就是这个
而调用的instantiate只有SimpleInstantiationStrategy实现了
源码如下
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
final Constructor> ctor, Object... args) {
//判断RootBeanDefinition是否有覆盖方法
if (!bd.hasMethodOverrides()) {
if (System.getSecurityManager() != null) {
// use own privileged to change accessibility (when security is on)
AccessController.doPrivileged((PrivilegedAction
可以看到,这里实例化又分为两种情况
- 如果有覆盖方法,也就是有replace属性,那就代表要进行代理,交给子类CglibSubclassingInstantiationStrategy策略进行创建,因为Cglib是默认的策略
- 如果没有覆盖方法,也就是没有代理,交给BeanUtils来进行创建
没有覆盖方法,就不需要Clb进行代理了,交由BeanUtils来进行实例化
源码如下
public staticT instantiateClass(Constructor ctor, Object... args) throws BeanInstantiationException { Assert.notNull(ctor, "Constructor must not be null"); try { //如果传进来的构造器为private类型 //则设置构造器的的accessible属性为true,让其可以被访问 ReflectionUtils.makeAccessible(ctor); //利用反射来进行创建Bean if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) { return KotlinDelegate.instantiateClass(ctor, args); } else { //获取构造器的参数的class类型 Class>[] parameterTypes = ctor.getParameterTypes(); //断言构造器使用参数数目与传进来的参数数目是否一样 Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters"); //建立object数组来存放处理后的参数 Object[] argsWithDefaultValues = new Object[args.length]; //遍历参数进行整理 for (int i = 0 ; i < args.length; i++) { //如果有参数为null if (args[i] == null) { //获取这个参数的类型 Class> parameterType = parameterTypes[i]; //判断这个参数是不是原始类型,即基本数据类型 //如果是基本数据类型,从DEFAULT_TYPE_VALUES中取默认值 //如果不是基本数据类型,那就为Null //不过一般都不会为null,因为前面对参数就进行处理了 argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null); } else { //如果参数不为null,存进数组中 argsWithDefaultValues[i] = args[i]; } } //使用反射的方法进行创建!!! return ctor.newInstance(argsWithDefaultValues); } } catch (InstantiationException ex) { throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex); } catch (IllegalAccessException ex) { throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex); } catch (IllegalArgumentException ex) { throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex); } catch (InvocationTargetException ex) { throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException()); } }
默认值的容器如下
可以看到里面仅仅只有5种,缺少了浮点型和字符型,那么对于浮点型和字符型为空的情况呢???
可见Spring对于浮点型和字符型是没有提供默认值的,如果来到这里发生浮点型和字符型为null,反射后会报IllegalArgumentException异常
拥有覆盖方法的实例化从上面可以看到,没有覆盖方法的实例化,其实就是使用反射来创建而已
下面看看如果有覆盖方法的实例化
对应的方法为instantiateWithMethodInjection,寓意为进行切入,也就是代理
可以看到,代理是交由CglibSubClassCreator去负责的,并且通过构造方法已经将RootBeanDefinition和BeanFactory注入进去了
源码如下
public Object instantiate(@Nullable Constructor> ctor, Object... args) {
//根据RootBeanDefinition一个增强class
//所谓的增强Class其实就是代理Class,因为被代理了,所以就是增强嘛
Class> subclass = createEnhancedSubclass(this.beanDefinition);
Object instance;
//判断构造器是否为空
if (ctor == null) {
//如果构造器为空,直接利用增强class来进行实例化
//BeanUtils其实就是使用反射去创建嘛,就不赘述了
instance = BeanUtils.instantiateClass(subclass);
}
else {
//如果构造器不为空
try {
//利用增强classs去获取构造器
Constructor> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
//利用构造器的增强class来实例化bean
instance = enhancedSubclassConstructor.newInstance(args);
}
catch (Exception ex) {
throw new BeanInstantiationException(this.beanDefinition.getBeanClass(),
"Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + "]", ex);
}
}
// SPR-10785: set callbacks directly on the instance instead of in the
// enhanced class (via the Enhancer) in order to avoid memory leaks.
//注意这里,这里注释说,将回调直接装在实例上,而不是增强class上,为了避免内存泄漏
Factory factory = (Factory) instance;
//给instace装了两个拦截器,
factory.setCallbacks(new Callback[] {NoOp.INSTANCE,
new LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),
new ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});
//返回增强的class,包含了装上的拦截器
return instance;
}
总结一下
对于使用构造方法去创建Bean,需要注意以下几点
- Spring虽然前期已经解析和加载大量数据,并且已经取得了构造器和参数,但并不是直接利用反射去做的,而是要进行判断,该bean需不需要进行增强,也就是是否要进行代理
- 如果不需要进行代理,直接交由BeanUtils利用反射来实例化出对象出来
- 如果需要进行代理
- 首先去根据RootBeanDefinition获取增强的class,即一个Enhancer.class
- 然后使用反射去创建该Enhancer
- 给该Enhancer装配两个拦截器
- LookupOverrideMethodInterceptor:对于Look-up属性的拦截器
- ReplaceOverrideMethodInterceptor:对于replace属性的拦截器
- 返回增强的实例Enhancer



