Spring

[Spring]Spring的getBean路线-createB

2021-01-31  本文已影响0人  AbstractCulture

前言

承上启下:

  1. Spring的refresh->finishBeanFactoryInitialization(容器初始化单例非延迟加载Bean的入口).
  2. beanFactory.preInstantiateSingletons();,Bean工厂开始加载Bean实例.
  3. 获取beanName列表,循环对每个beanName进行getBean操作.
  4. getBean中调用了doGetBean进行了一些创建Bean的前置处理.最终在getSingleton中调用了createBean进行Bean的创建.

OK,下面进入今天的主题-createBean.

createBean的总体流程

1. resolveBeanClass-解析Bean类型,获取Bean的Class.

    protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException {

        if (logger.isTraceEnabled()) {
            logger.trace("Creating instance of bean '" + beanName + "'");
        }
        RootBeanDefinition mbdToUse = mbd;

        // 确认当前的Bean类是可以被解析的,并且支持克隆BeanDefinition,merged的BeanDefinition不在此方法的考虑范围
        // 进入到里面,会发现器通过了类加载器进行了Class的获取
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            // 克隆一份BeanDefinition,用来设置上加载出来的对象
            // 采用副本的原因是某些类可能需要动态加载Class
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }
        // 省略若干代码
}

容器在前面已经加载并注册好了BeanDefinition,它描述了关于Bean的信息,在此处Spring要开始将自己抽象出来的BeanDefinition进行解析.这里思考一个问题,为什么Spring在加载Bean的时候选择了RootBeanDefinition进行解析,而不是之前在加载BeanDefinition的时候反复说到的GenericBeanDefinition?

RootBeanDefinition对应的是Java中的继承体系而制造的复合BeanDefinition(Spring在定义Bean时,也支持定义继承关系).从各种容器加载出来的BeanDefinition,最终都会通过getMergedLocalBeanDefinition转化成RootBeanDefinition.

RootBeanDefinition可以合成有继承关系的BeanDefinition(如果没有继承关系,那么自己便是代表parent).

这里推荐一篇文章,希望可以带来更多的思考: 【小家Spring】Spring IoC容器中核心定义之------BeanDefinition深入分析(RootBeanDefinition、ChildBeanDefinition...)

OK,回到主题,拿到传进来的RootBeanDefinition后,Spring需要确认当前的Bean类是可以被解析的,即是否能通过类加载器进行载入.对于注解容器来说,在组件扫描的时候就通过ResourceLoader进行了资源的定位,所以在这里是可以确认可以被解析的.
考虑到健全性,Spring还是谨慎地进行了校验,毕竟不是所有的BeanDefinition都是通过注解容器加载的.

    protected Class<?> resolveBeanClass(RootBeanDefinition mbd, String beanName, Class<?>... typesToMatch)
            throws CannotLoadBeanClassException {

        try {
            // 如果当前BeanDefinition存储beanClass属于Class实例,直接返回
            if (mbd.hasBeanClass()) {
                return mbd.getBeanClass();
            }
            if (System.getSecurityManager() != null) {
                return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>)
                        () -> doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
            }
            else {
                // 如果当前BeanDefinition没有存储Class实例,那么尝试解析
                return doResolveBeanClass(mbd, typesToMatch);
            }
        }
        catch (PrivilegedActionException pae) {
            ClassNotFoundException ex = (ClassNotFoundException) pae.getException();
            throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
        }
        catch (ClassNotFoundException ex) {
            throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
        }
        catch (LinkageError err) {
            throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err);
        }
    }
    private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)
            throws ClassNotFoundException {

        ClassLoader beanClassLoader = getBeanClassLoader();
        ClassLoader dynamicLoader = beanClassLoader;
        boolean freshResolve = false;

        if (!ObjectUtils.isEmpty(typesToMatch)) {
            // When just doing type checks (i.e. not creating an actual instance yet),
            // use the specified temporary class loader (e.g. in a weaving scenario).
            ClassLoader tempClassLoader = getTempClassLoader();
            if (tempClassLoader != null) {
                dynamicLoader = tempClassLoader;
                freshResolve = true;
                if (tempClassLoader instanceof DecoratingClassLoader) {
                    DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
                    for (Class<?> typeToMatch : typesToMatch) {
                        dcl.excludeClass(typeToMatch.getName());
                    }
                }
            }
        }
        // 获取BeanDefinition的className.
        String className = mbd.getBeanClassName();
        if (className != null) {
            // 根据className解析成表达式
            Object evaluated = evaluateBeanDefinitionString(className, mbd);
            if (!className.equals(evaluated)) {
                // A dynamically resolved expression, supported as of 4.2...
                if (evaluated instanceof Class) {
                    return (Class<?>) evaluated;
                }
                else if (evaluated instanceof String) {
                    className = (String) evaluated;
                    freshResolve = true;
                }
                else {
                    throw new IllegalStateException("Invalid class name expression result: " + evaluated);
                }
            }
            if (freshResolve) {
                // When resolving against a temporary class loader, exit early in order
                // to avoid storing the resolved Class in the bean definition.
                if (dynamicLoader != null) {
                    try {
                        // 如果解析后的表达式为Class则直接返回
                        return dynamicLoader.loadClass(className);
                    }
                    catch (ClassNotFoundException ex) {
                        if (logger.isTraceEnabled()) {
                            logger.trace("Could not load class [" + className + "] from " + dynamicLoader + ": " + ex);
                        }
                    }
                }
                // 反射工具类加载Class
                return ClassUtils.forName(className, dynamicLoader);
            }
        }

        // Resolve regularly, caching the result in the BeanDefinition...
        return mbd.resolveBeanClass(beanClassLoader);
    }

这里Spring会获取到当前工厂的类加载器,然后从BeanDefinition中获取className.Spring会先对className做表达式解析,如果不是通过表达式进行解析,那么调用ClassUtils.forName(className, dynamicLoader);,如果className不存在,再使用类加载器进行加载.类于类加载器是一一对应的关系,Spring需要找到可以加载该类的类加载器,然后加载出Class对象.

2. 检查和准备Bean中的方法覆盖-prepareMethodOverrides

        // Prepare method overrides.
        // 检查和准备Bean中的方法覆盖
        try {
            mbdToUse.prepareMethodOverrides();
        }

主要针对lookup methods做校验和方法覆盖。现在用得比较少了.
如果对Lookup方法注入有兴趣,可以在Spring的官网查看: 点我前往

    public void prepareMethodOverrides() throws BeanDefinitionValidationException {
        // Check that lookup methods exist and determine their overloaded status.
        // 检查查找方法是否存在,并确定其重载状态。
        if (hasMethodOverrides()) {
            getMethodOverrides().getOverrides().forEach(this::prepareMethodOverride);
        }
    }

验证并准备给定的方法是否被重写。检查是否存在具有指定名称的方法,如果找不到该方法,则将其标记为未重载。

    protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
        int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
        if (count == 0) {
            throw new BeanDefinitionValidationException(
                    "Invalid method override: no method with name '" + mo.getMethodName() +
                    "' on class [" + getBeanClassName() + "]");
        }
        // 如果不存在重载,在使用CGLIB增强阶段就不需要校验了
        else if (count == 1) {
            // Mark override as not overloaded, to avoid the overhead of arg type checking.
            // 将替代标记为未过载,以避免arg类型检查的开销。
            mo.setOverloaded(false);
        }
    }

3. 激活Bean实例化前的后置处理器-resolveBeforeInstantiation

        try {
            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
            // 解析BeanPostProcessors的BeanPostProcessorsBeforeInstantiation,试图返回一个需要创建Bean的代理对象
            // resolveBeforeInstantiation只针对有自定义的targetsource.
            // 因为自定义的targetsource不是Spring的bean,那么后续的初始化与该bean无关
            // 因此直接可以进行代理
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                    "BeanPostProcessor before instantiation of bean failed", ex);
        }
    protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
        Object bean = null;
        // 如果beforeInstantiationResolved为false
        if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
            // Make sure bean class is actually resolved at this point.
            // 如果注册了InstantiationAwareBeanPostProcessors的BeanPostProcessor.
            if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
                Class<?> targetType = determineTargetType(beanName, mbd);
                if (targetType != null) {
                    // 执行实现了该后置处理器接口的类中postProcessBeforeInitialization方法
                    // Spring在这里使用了责任链模式,如果有一个后置处理器可以返回Object,就会马上跳出循环
                    // 同时,如果第三方框架在此后置处理器对Bean执行了操作,那么将不会进入到doCreateBean中了.
                    // 注意传参,这里传入的是一个class和beanName.
                    bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                    if (bean != null) {
                        bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                    }
                }
            }
            mbd.beforeInstantiationResolved = (bean != null);
        }
        return bean;
    }

如果当前的Bean实现了InstantiationAwareBeanPostProcessor接口,并且在postProcessBeforeInstantiation中返回了Object,那么Spring将不会执行doCreateBean进行实例化,而是将当前用户返回的bean实例直接返回。
AbstractAutoProxyCreator这个AOP代理的BeanPostProcessor便是这样做的.
执行完before的操作后,如果返回了实例,那么继续执行after的操作.
其中,before和after的执行逻辑有点区别:
before方法执行的中断条件:

                Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
                if (result != null) {
                    return result;
                }

after方法执行的中断条件:

            Object current = processor.postProcessAfterInitialization(result, beanName);
            if (current == null) {
                return result;
            }

关注这个BeanPostPorcessor,在后续的学习中,我们仍能在过滤器中学习到这种职责链的设计原则.
我们来看看InstantiationAwareBeanPostProcessor的接口清单.默认返回null.

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

    @Nullable
    default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        return null;
    }

    default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        return true;
    }
}

4. 开始创建Bean-doCreateBean

OK,再梳理一下思路,从createBean中,Spring分析了当前的Class是否能被类加载器加载,如果可以加载,返回当前BeanDefinitino的Class对象,接着进行了Lookup method的检查,最后激活了InstantiationAwareBeanPostProcessors的方法,如果以上方法都没中断,那么Spring将进行Bean的实例化-doCreateBean.

        try {
            // 创建bean的入口
            Object beanInstance = doCreateBean(beanName, mbdToUse, args);
            if (logger.isTraceEnabled()) {
                logger.trace("Finished creating instance of bean '" + beanName + "'");
            }
            return beanInstance;
        }
        catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
            // A previously detected exception with proper bean creation context already,
            // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
            throw ex;
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
        }

总结

doCreateBean篇幅较长,将拆分几篇文章进行讲解,如果觉得不错,请关注我的博客~

上一篇 下一篇

猜你喜欢

热点阅读