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

2020-06-26  本文已影响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有俩个实现类:

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方法,可以看到在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注解:

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的使用较少,个人认为稍微理解一下就行,不必过于纠结细节,否则,学习起来进度应该相当缓慢,进而影响坚持下去的动力。

上一篇下一篇

猜你喜欢

热点阅读