美文网首页
spring容器之bean的初始化策略(Instantiatio

spring容器之bean的初始化策略(Instantiatio

作者: 会上树的程序猿 | 来源:发表于2019-08-11 22:22 被阅读0次

    在看InstantiationStrategy之前我们先来简单的回顾下我们bean的实例化过程:

    • 我们在AbstractAutowireCapableBeanFactory#doCreateBean(...)方法中完成了bean的创建过程,期间在该方法中有bean的初始化 属性的设置以及bean的实例化入口,其中在bean的实例化过程中是根据bean的类型进行判断,如果当前bean是单例,从factoryBeanInstanceCach中获取,反之通过#createBeanInstance(...)来创建.
    • 如果是通过#createBeanInstance(...)方法进行bean实例的创建:
      - 通过Supplier来判断,该Supplier不为null,则通过方法#obtainFromSupplier(...)进行bean的实例化操作.
      - 如果factory不为null,则调用 #instantiateUsingFactoryMethod(...) 方法来实例化Bean.
      - 如果都不是上面的两者,则调用默认的方法#instantiateBean(...)来完成bean的实例化操作.

    不过上述是如何操作的过程,其最终都会经过InstantiationStrategy的instantiate(....)方法,接下来我们看一下该InstantiationStrategy接口:

    InstantiationStrategy
    public interface InstantiationStrategy {
    
    /**
     * 默认的构造方法
     * @param bd
     * @param beanName
     * @param owner
     * @return
     * @throws BeansException
     */
    Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner)throws BeansException;
    /**
     * 指定构造方法
     * @param bd
     * @param beanName
     * @param owner
     * @param ctor
     * @param args
     * @return
     * @throws BeansException
     */
    
    Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
            Constructor<?> ctor, Object... args) throws BeansException;
    /**
     * 通过指定的工厂方法
     * @param bd
     * @param beanName
     * @param owner
     * @param factoryBean
     * @param factoryMethod
     * @param args
     * @return
     * @throws BeansException
     */
    Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
            @Nullable Object factoryBean, Method factoryMethod, Object... args)
            throws BeansException;
    

    可以看到的是InstantiationStrategy接口为Bean的初始化提供了三种策略化方法,根据bean的不同选择不同的策略模式进行实例化过程,我们分别来看:

    1.默认的构造方法
    public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
        // Don't override the class with CGLIB if no overrides.
        //如果没有方法被覆盖,通过BeanUtils#instantiateClass来初始化(实质是利用反射来创建)
        if (!bd.hasMethodOverrides()) {
            Constructor<?> constructorToUse;
            //加锁
            synchronized (bd.constructorArgumentLock) {
                //获取构造方法constructorToUse
                constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
                if (constructorToUse == null) {
                    //获取Bean的class的对象
                    final Class<?> clazz = bd.getBeanClass();
                    //如果clazz是接口类型的,直接抛BeanInstantiationException异常
                    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();
                        }
                        //将constructorToUse赋给resolvedConstructorOrFactoryMethod属性
                        bd.resolvedConstructorOrFactoryMethod = constructorToUse;
                    }
                    catch (Throwable ex) {
                        throw new BeanInstantiationException(clazz, "No default constructor found", ex);
                    }
                }
            }
            //通过BeanUtils直接使用构造器对象实例化Bean对象
            return BeanUtils.instantiateClass(constructorToUse);
        }
        else {
            // Must generate CGLIB subclass.
            //生成CGLIB创建的子类对象
            return instantiateWithMethodInjection(bd, beanName, owner);
        }
    }
    

    在构造方法策略模式中,首先是判断是否有方法被覆盖,如果没有则直接通过反射的方式来创建,如果有的话则通过CGLIB来实例化对象.

    2.指定的构造方法
    public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
            final Constructor<?> ctor, Object... args) {
        //判断是否有方法需要重载
        if (!bd.hasMethodOverrides()) {
            if (System.getSecurityManager() != null) {
                // use own privileged to change accessibility (when security is on)
                //设置访问权限
                AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                    ReflectionUtils.makeAccessible(ctor);
                    return null;
                });
            }
            //通过 BeanUtils直接使用构造器对象实例化Bean对象
            return BeanUtils.instantiateClass(ctor, args);
        }
        else {
            //2初始化CGLB对象
            return instantiateWithMethodInjection(bd, beanName, owner, ctor, args);
        }
    }
    

    通过指定的构造方法我们可以发现跟默认的构造方法类似

    3.工厂方法
    public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
            @Nullable Object factoryBean, final Method factoryMethod, Object... args) {
    
        try {
            //设置方法的访问权限
            if (System.getSecurityManager() != null) {
                AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                    ReflectionUtils.makeAccessible(factoryMethod);
                    return null;
                });
            }
            else {
                ReflectionUtils.makeAccessible(factoryMethod);
            }
            //获取之前的方法
            Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
            try {
                //将新的工厂方法保存到currentlyInvokedFactoryMethod中
                currentlyInvokedFactoryMethod.set(factoryMethod);
                //创建bean对象
                Object result = factoryMethod.invoke(factoryBean, args);
                //没创建成功,则创建一个nullBean来代替
                if (result == null) {
                    result = new NullBean();
                }
                //创建成功的话,直接返回
                return result;
            }
            finally {
                if (priorInvokedFactoryMethod != null) {
                    //覆盖之前的方法
                    currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);
                }
                else {
                    currentlyInvokedFactoryMethod.remove();
                }
            }
        }
        //后面都是些异常处理
        catch (IllegalArgumentException ex) {
            throw new BeanInstantiationException(factoryMethod,
                    "Illegal arguments to factory method '" + factoryMethod.getName() + "'; " +
                    "args: " + StringUtils.arrayToCommaDelimitedString(args), ex);
        }
        catch (IllegalAccessException ex) {
            throw new BeanInstantiationException(factoryMethod,
                    "Cannot access factory method '" + factoryMethod.getName() + "'; is it public?", ex);
        }
        catch (InvocationTargetException ex) {
            String msg = "Factory method '" + factoryMethod.getName() + "' threw exception";
            if (bd.getFactoryBeanName() != null && owner instanceof ConfigurableBeanFactory &&
                    ((ConfigurableBeanFactory) owner).isCurrentlyInCreation(bd.getFactoryBeanName())) {
                msg = "Circular reference involving containing bean '" + bd.getFactoryBeanName() + "' - consider " +
                        "declaring the factory method as static for independence from its containing instance. " + msg;
            }
            throw new BeanInstantiationException(factoryMethod, msg, ex.getTargetException());
        }
    }
    

    工厂方法的处理更简单直接,不用考虑,直接利用反射的方式来初始化对象

    CglibSubclassingInstantiationStrategy

    关于CglibSubclassingInstantiationStrategy,该类继承于SimpleInstantiationStrategy与此同时该类也是spring默认的实例化bean的策略,也是CGLIB实例化bean的委托对象的实现类.

    在我们的SimpleInstantiationStrategy类中有这样一段代码:

    protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
        throw new UnsupportedOperationException("Method Injection not supported in SimpleInstantiationStrategy");
    }
    

    同样的在CglibSubclassingInstantiationStrategy子类中:

    @Override
    protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
        return instantiateWithMethodInjection(bd, beanName, owner, null);
    }
    
    @Override
    protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
            @Nullable Constructor<?> ctor, Object... args) {
    
        // Must generate CGLIB subclass...
        //生成一个CGLB子类对象
        return new CglibSubclassCreator(bd, owner).instantiate(ctor, args);
    }
    

    我们可以发现,显然子类CglibSubclassingInstantiationStrategy中对该方法进行了增强处理.其实例化bean的时候实际上是由CglibSubclassCreator来实现:

        public Object instantiate(@Nullable Constructor<?> ctor, Object... args) {
            //创建一个cglb的代理类
            Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
            Object instance;
            //<2>如果当前构造器不存在,通过BeanUtils调用默认构造器来创建
            if (ctor == null) {
                instance = BeanUtils.instantiateClass(subclass);
            }
            else {
                try {
                    //获取代理对象的构造器
                    Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
                    //创建实例
                    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.
            //避免内存泄露,直接在bean实例上设置回调
            Factory factory = (Factory) instance;
            factory.setCallbacks(new Callback[] {NoOp.INSTANCE,
                    new LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),
                    new ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});
            return instance;
        }
    

    我们可以发现,一进入方法通过调用#createEnhancedSubclass(...)来提供BeanDefinition创建bean的增强子类,代码如下:

    /**
         * Create an enhanced subclass of the bean class for the provided bean
         * definition, using CGLIB.
         */
        private Class<?> createEnhancedSubclass(RootBeanDefinition beanDefinition) {
            //创建Enhancer对象
            Enhancer enhancer = new Enhancer();
            //设置当前bean的class类型
            enhancer.setSuperclass(beanDefinition.getBeanClass());
            //设置spring的命名策略
            enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
            //设置生成策略
            if (this.owner instanceof ConfigurableBeanFactory) {
                ClassLoader cl = ((ConfigurableBeanFactory) this.owner).getBeanClassLoader();
                enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(cl));
            }
            // 过滤,自定义逻辑来指定调用的callback下标
            enhancer.setCallbackFilter(new MethodOverrideCallbackFilter(beanDefinition));
            enhancer.setCallbackTypes(CALLBACK_TYPES);
            return enhancer.createClass();
        }
    

    在<2>处,如果ctor为null时,则通过BeanUtils#instantiateClass(subclass)来实例化bean,否则则根据构造函数类型获取具体的构造器,调用Constructor#newInstance(args) 方法来实例化.

    MethodOverrideCallbackFilter

    在我们的#createEnhancedSubclass(...)方法中的末尾,我们通过过滤,自定义逻辑来指定调用的callback下标,也就是以下代码:

    enhancer.setCallbackFilter(new MethodOverrideCallbackFilter(beanDefinition));
    enhancer.setCallbackTypes(CALLBACK_TYPES);
    

    我们发现在设置CallbackFilter属性时首先是创建一个MethodOverrideCallbackFilter对象,我们来看看它到底是什么?

    • 原来发现MethodOverrideCallbackFilter继承于CglibIdentitySupport同时实现了CallbackFilter接口.
    • 其次CallbackFilter是一个CGLIB 的一个回调过滤器接口.
    • CglibIdentitySupport 则为 CGLIB 提供 #hashCode() 和 #equals(Object o) 方法,以确保 CGLIB 不会为每个 Bean 生成不同的类.
    • MethodOverrideCallbackFilter 实现 CallbackFilter 的 #accept(Method method) 方法:
    public int accept(Method method) {
            MethodOverride methodOverride = getBeanDefinition().getMethodOverrides().getOverride(method);
            if (logger.isTraceEnabled()) {
                logger.trace("Override for '" + method.getName() + "' is [" + methodOverride + "]");
            }
            if (methodOverride == null) {
                return PASSTHROUGH;
            }
            else if (methodOverride instanceof LookupOverride) {
                return LOOKUP_OVERRIDE;
            }
            else if (methodOverride instanceof ReplaceOverride) {
                return METHOD_REPLACER;
            }
            throw new UnsupportedOperationException("Unexpected MethodOverride subclass: " +
                    methodOverride.getClass().getName());
        }
    

    在accept方法中,通过其methodOverride返回的值来判断,其中上述代码中的PASSTHROUGH 和 LOOKUP_OVERRIDE以及METHOD_REPLACER为Callback数组的下标,这里的数组为CALLBACK_TYPES数组,代码如下:

    private static final Class<?>[] CALLBACK_TYPES = new Class<?>[]
                {NoOp.class, LookupOverrideMethodInterceptor.class, ReplaceOverrideMethodInterceptor.class};
    

    在上述的数组中我们看到定义了两个拦截器,接下来我们分别来看:

    LookupOverrideMethodInterceptor
    /**
     * CGLIB MethodInterceptor to override methods, replacing them with an
     * implementation that returns a bean looked up in the container.
     */
    private static class LookupOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor {
    
        private final BeanFactory owner;
    
        public LookupOverrideMethodInterceptor(RootBeanDefinition beanDefinition, BeanFactory owner) {
            super(beanDefinition);
            this.owner = owner;
        }
    
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
            // Cast is safe, as CallbackFilter filters are used selectively.
            //通过method来获取LookupOverride对象
            LookupOverride lo = (LookupOverride) getBeanDefinition().getMethodOverrides().getOverride(method);
            Assert.state(lo != null, "LookupOverride not found");
            //获取参数
            Object[] argsToUse = (args.length > 0 ? args : null);  // if no-arg, don't insist on args at all
            //获取bean
            if (StringUtils.hasText(lo.getBeanName())) {
                //如果参数argsToUse不为null,通过name去获取
                return (argsToUse != null ? this.owner.getBean(lo.getBeanName(), argsToUse) :
                        this.owner.getBean(lo.getBeanName()));
            }
            else {
                //通过type去获取
                return (argsToUse != null ? this.owner.getBean(method.getReturnType(), argsToUse) :
                        this.owner.getBean(method.getReturnType()));
            }
        }
    }
    
    ReplaceOverrideMethodInterceptor
    /**
     * CGLIB MethodInterceptor to override methods, replacing them with a call
     * to a generic MethodReplacer.
     */
    private static class ReplaceOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor {
    
        private final BeanFactory owner;
    
        public ReplaceOverrideMethodInterceptor(RootBeanDefinition beanDefinition, BeanFactory owner) {
            super(beanDefinition);
            this.owner = owner;
        }
    
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
            //通过method来获取ReplaceOverride对象
            ReplaceOverride ro = (ReplaceOverride) getBeanDefinition().getMethodOverrides().getOverride(method);
            Assert.state(ro != null, "ReplaceOverride not found");
            // TODO could cache if a singleton for minor performance optimization
            //获取MethodReplacer对象
            MethodReplacer mr = this.owner.getBean(ro.getMethodReplacerBeanName(), MethodReplacer.class);
            //进行替换操作
            return mr.reimplement(obj, method, args);
        }
    }
    

    到这里,关于初始化的策略模式知识我们讲到这里了...

    相关文章

      网友评论

          本文标题:spring容器之bean的初始化策略(Instantiatio

          本文链接:https://www.haomeiwen.com/subject/pidgdctx.html