美文网首页
Spring源码解析(二十)-Bean 的实例化策略Instan

Spring源码解析(二十)-Bean 的实例化策略Instan

作者: 秋水畏寒 | 来源:发表于2020-06-26 22:27 被阅读0次

    怀念过去,不满当下,迷惑未来,那么,努力吧!总得找个方式让自己转移一下注意力。

    Spring版本

    5.2.5.RELEASE

    参考

    《芋道源码》

    源码解读

    1 InstantiationStrategy

    《Spring源码解析(九)-创建bean实例》中,使用了instantiate方法来执行Spring Bean实例化策略:

    // 如果候选方法只有一个,并且没有要求参数,且有无参构造方法,那么,满足创建bean的要求,进行实例化
                if (candidates.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
                    Method uniqueCandidate = candidates.get(0);
                    // 如果唯一的候选方法参数个数为=0,满足mbd的无参构造方法
                    if (uniqueCandidate.getParameterCount() == 0) {
                        mbd.factoryMethodToIntrospect = uniqueCandidate;
                        synchronized (mbd.constructorArgumentLock) {
                            mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
                            mbd.constructorArgumentsResolved = true;
                            mbd.resolvedConstructorArguments = EMPTY_ARGS;
                        }
                        bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS));
                        return bw;
                    }
                }
    

    其中,instantiate方法实现如下:

    private Object instantiate(String beanName, RootBeanDefinition mbd,
                @Nullable Object factoryBean, Method factoryMethod, Object[] args) {
    
            try {
                if (System.getSecurityManager() != null) {
                    return AccessController.doPrivileged((PrivilegedAction<Object>) () ->
                            this.beanFactory.getInstantiationStrategy().instantiate(
                                    mbd, beanName, this.beanFactory, factoryBean, factoryMethod, args),
                            this.beanFactory.getAccessControlContext());
                }
                else {
                    // 通过反射调用对应方法进行实例化
                    return this.beanFactory.getInstantiationStrategy().instantiate(
                            mbd, beanName, this.beanFactory, factoryBean, factoryMethod, args);
                }
            }
            catch (Throwable ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Bean instantiation via factory method failed", ex);
            }
        }
    

    可以看到通过getInstantiationStrategy()方法调用了对应的实例化策略进行实例化,getInstantiationStrategy()返回一个InstantiationStrategy对象,查看源码可以发现:InstantiationStrategy接口定义了 Spring Bean 实例化的策略,有具体以下三种实现策略:

    • 无参构造
    • 有参构造
    • 工厂方法
    public interface InstantiationStrategy {
    
        // 无参构造
        Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner)
                throws BeansException;
    
        // 有参构造
        Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
                Constructor<?> ctor, Object... args) throws BeansException;
    
        // 工厂方法
        Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
                @Nullable Object factoryBean, Method factoryMethod, Object... args)
                throws BeansException;
    
    }
    

    InstantiationStrategy有俩个实现类:

    • SimpleInstantiationStrategy
    • CglibSubclassingInstantiationStrategy

    2 SimpleInstantiationStrategy

    该类实现了InstantiationStrategy的三个方法

    2.1 无参构造

        @Override
        public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
            // Don't override the class with CGLIB if no overrides.
            // 如果没有replace-method、lookup-method,以及使用@Lookup注解,那么使用反射进行实例化
            if (!bd.hasMethodOverrides()) {
                Constructor<?> constructorToUse;
                synchronized (bd.constructorArgumentLock) {
                    // 获取构造方法
                    constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
                    // 未能获取到构造方法,尝试通过clazz获取
                    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 {
                // Must generate CGLIB subclass.
                // 否则,创建cglib子类实例化
                return instantiateWithMethodInjection(bd, beanName, owner);
            }
        }
    

    首先判断是否存在replace-methodlookup-method,以及使用@Lookup注解:

    • 不存在,获取构造方法,之后通过构造方法进行实例化
    • 存在,调用instantiateWithMethodInjection方法

    查看instantiateWithMethodInjection方法,可以看到在SimpleInstantiationStrategy中是默认不实现的:

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

    交由CglibSubclassingInstantiationStrategy进行实现

    2.2 有参构造

        @Override
        public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
                final Constructor<?> ctor, Object... args) {
    
            // 如果没有replace-method、lookup-method,以及使用@Lookup注解,那么使用反射进行实例化
            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;
                    });
                }
                // 使用cror构造方法通过反射实例化
                return BeanUtils.instantiateClass(ctor, args);
            }
            else {
                // 否则,创建cglib子类实例化
                return instantiateWithMethodInjection(bd, beanName, owner, ctor, args);
            }
        }
    

    同样,判断是否存在replace-methodlookup-method,以及使用@Lookup注解:

    • 不存在,通过传入的构造方法进行实例化
    • 存在,调用instantiateWithMethodInjection方法

    2.3 工厂方法

        @Override
        public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
                @Nullable Object factoryBean, final Method factoryMethod, Object... args) {
    
            try {
                // 设置method方法可访问
                if (System.getSecurityManager() != null) {
                    AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                        ReflectionUtils.makeAccessible(factoryMethod);
                        return null;
                    });
                }
                else {
                    ReflectionUtils.makeAccessible(factoryMethod);
                }
    
                Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
                try {
                    currentlyInvokedFactoryMethod.set(factoryMethod);
                    // 通过反射调用工厂方法获取实例
                    Object result = factoryMethod.invoke(factoryBean, args);
                    if (result == null) {
                        result = new NullBean();
                    }
                    return result;
                }
                finally {
                    if (priorInvokedFactoryMethod != null) {
                        currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);
                    }
                    else {
                        currentlyInvokedFactoryMethod.remove();
                    }
                }
            }
        // 省略
    }
    

    先通过ReflectionUtils.makeAccessible(factoryMethod)设置工厂方法可以访问,之后通过Object result = factoryMethod.invoke(factoryBean, args)反射调用工厂方法获取实例

    3 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...
            return new CglibSubclassCreator(bd, owner).instantiate(ctor, args);
        }
    

    在第二个重载方法中,可以看到构造了一个CglibSubclassCreator对象,之后通过instantiate进行了实例化:

            public Object instantiate(@Nullable Constructor<?> ctor, Object... args) {
                // 创建代理类
                Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
                Object instance;
                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.
                Factory factory = (Factory) instance;
                factory.setCallbacks(new Callback[] {NoOp.INSTANCE,
                        new LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),
                        new ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});
                return instance;
            }
    

    3.1 createEnhancedSubclass

            private Class<?> createEnhancedSubclass(RootBeanDefinition beanDefinition) {
                Enhancer enhancer = new Enhancer();
                enhancer.setSuperclass(beanDefinition.getBeanClass());
                // 设置命名策略
                enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
                if (this.owner instanceof ConfigurableBeanFactory) {
                    ClassLoader cl = ((ConfigurableBeanFactory) this.owner).getBeanClassLoader();
                    enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(cl));
                }
                // 添加回调过滤器
                enhancer.setCallbackFilter(new MethodOverrideCallbackFilter(beanDefinition));
                enhancer.setCallbackTypes(CALLBACK_TYPES);
                return enhancer.createClass();
            }
    

    MethodOverrideCallbackFilter是用来定义 CGLIB 回调过滤方法的拦截器行为,它继承 CglibIdentitySupport实现CallbackFilter 接口:

        private static class MethodOverrideCallbackFilter extends CglibIdentitySupport implements CallbackFilter {
    
            private static final Log logger = LogFactory.getLog(MethodOverrideCallbackFilter.class);
    
            public MethodOverrideCallbackFilter(RootBeanDefinition beanDefinition) {
                super(beanDefinition);
            }
    
            @Override
            public int accept(Method method) {
                MethodOverride methodOverride = getBeanDefinition().getMethodOverrides().getOverride(method);
                if (logger.isTraceEnabled()) {
                    logger.trace("MethodOverride for " + method + ": " + 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方法,返回的PASSTHROUGHLOOKUP_OVERRIDEMETHOD_REPLACER对应的是CALLBACK_TYPES数组的元素下标:

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

    可以看到这里定义了LookupOverrideMethodInterceptorReplaceOverrideMethodInterceptor,通过这俩个拦截器对lookup-methodreplace-method进行了处理。

    3.2 LookupOverrideMethodInterceptor

        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.
                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
                // 通过getBean获取实例,然后返回该实例,以起到替换作用
                if (StringUtils.hasText(lo.getBeanName())) {
                    return (argsToUse != null ? this.owner.getBean(lo.getBeanName(), argsToUse) :
                            this.owner.getBean(lo.getBeanName()));
                }
                else {
                    return (argsToUse != null ? this.owner.getBean(method.getReturnType(), argsToUse) :
                            this.owner.getBean(method.getReturnType()));
                }
            }
        }
    

    3.3 ReplaceOverrideMethodInterceptor

        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 {
                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 mr = this.owner.getBean(ro.getMethodReplacerBeanName(), MethodReplacer.class);
                return mr.reimplement(obj, method, args);
            }
        }
    

    总结

    本文主要学习了spring实例化bean对几种策略,及其对lookup-methodreplace-method的代理处理,不过平时对于lookup-methodreplace-method的使用较少,个人认为稍微理解一下就行,不必过于纠结细节,否则,学习起来进度应该相当缓慢,进而影响坚持下去的动力。

    相关文章

      网友评论

          本文标题:Spring源码解析(二十)-Bean 的实例化策略Instan

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