• Spring源码解析(四) -- getBean(String name, Class<T> requiredType)


    前言

      早在分析beanFactoryPostProcessor的时候,就出现了BeanFactory.getBean方法,因为每一个beanFactoryPostProcessor也是spring管理的bean,也是要经过spring实例化和初始化才能够使用的,只是当时该方法还不是要分析的重点。

      这里多提一句 在初始化过程中容易被忽略的一个方法

    public void refresh() throws BeansException, IllegalStateException {
            synchronized (this.startupShutdownMonitor) {
                // Prepare this context for refreshing.
                prepareRefresh();
    
                // Tell the subclass to refresh the internal bean factory.
                ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
                // Prepare the bean factory for use in this context.
                prepareBeanFactory(beanFactory);
    
                try {
                    // Allows post-processing of the bean factory in context subclasses.
                    postProcessBeanFactory(beanFactory);
    
                    // Invoke factory processors registered as beans in the context.
                    invokeBeanFactoryPostProcessors(beanFactory);
    
                    // Register bean processors that intercept bean creation.
                    registerBeanPostProcessors(beanFactory);
    
                    // Initialize message source for this context.
                    initMessageSource();
    
                    // Initialize event multicaster for this context.
                    initApplicationEventMulticaster();
    
                    // Initialize other special beans in specific context subclasses.
                    onRefresh();
    
                    // Check for listener beans and register them.
                    registerListeners();

    这一步是注册listener,一般可以监听spring的context容器启动完成等情况的,一般开发者也不太会用到

    1 查询缓存

    final String beanName = transformedBeanName(name);
            Object bean;
    
            // Eagerly check singleton cache for manually registered singletons.
            Object sharedInstance = getSingleton(beanName);
            if (sharedInstance != null && args == null) {
                if (logger.isDebugEnabled()) {
                    if (isSingletonCurrentlyInCreation(beanName)) {
                        logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                                "' that is not fully initialized yet - a consequence of a circular reference");
                    }
                    else {
                        logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
                    }
                }
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
            }

    这部分是先查询该bean是否在之前有过缓存,有就直接使用了,还有一种情况是该bean是一个beanFactory那么就调用beanFactory的getObject方法

    2 从父容器中初始化bean

    // Fail if we're already creating this bean instance:
                // We're assumably within a circular reference.
                if (isPrototypeCurrentlyInCreation(beanName)) {
                    throw new BeanCurrentlyInCreationException(beanName);
                }
    
                // Check if bean definition exists in this factory.
                BeanFactory parentBeanFactory = getParentBeanFactory();
                if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                    // Not found -> check parent.
                    String nameToLookup = originalBeanName(name);
                    if (args != null) {
                        // Delegation to parent with explicit args.
                        return (T) parentBeanFactory.getBean(nameToLookup, args);
                    }
                    else {
                        // No args -> delegate to standard getBean method.
                        return parentBeanFactory.getBean(nameToLookup, requiredType);
                    }
                }

    代码的作用比较清晰

    3 开始实例化

    try {
                    final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                    checkMergedBeanDefinition(mbd, beanName, args);
    
                    // Guarantee initialization of beans that the current bean depends on.
                    String[] dependsOn = mbd.getDependsOn();
                    if (dependsOn != null) {
                        for (String dep : dependsOn) {
                            if (isDependent(beanName, dep)) {
                                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                        "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                            }
                            registerDependentBean(dep, beanName);
                            getBean(dep);
                        }
                    }

      先说一说这个BeanDefinition,BD只是一个接口,常用的实现类是

    public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
            implements BeanDefinition, Cloneable 

      比如在容器启动的最开始通过BeanDefinitionReader读取的最原始的bd就都是AbstractBeanDefinition

      到这里也能够看到 会把 AbstractBeanDefinition 变成了 RootBeanDefinition 

      注意这里的mergedBeanDefinition,根据文档beanDefinition也是有继承关系的。注意不是真的类的继承关系,我写的代码测试B继承A,但是还是两个BeanDefinition。

     mergedBeanDefinitions 是在 AbstractBeanFactory里的
    private final Map<String, RootBeanDefinition> mergedBeanDefinitions =
                new ConcurrentHashMap<String, RootBeanDefinition>(256);

      而保存所有的beanDefinition是在 DefaultListableBeanFactory的 

    /** Map of bean definition objects, keyed by bean name */
        private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);

      总之一句话,一个beanDefinition会经过转换变成mergedBeanDefinition,尽管大多数的beanDefinition还是保持着原样。那么什么情况下会出现需要mergedBeanDefinition呢?如下这种,当然绝大多数没人这么用。

    <bean id="baseUser" class="com.yh.stu.spring.sourcestu._01ioc.ch1_base.mergebd.BaseUser">
        </bean>
        <bean id="user" class="com.yh.stu.spring.sourcestu._01ioc.ch1_base.mergebd.User" parent="baseUser"/>

      而接下来的实例化一个bean就是使用mergedBeanDefinition。

      这里做的第二件事是实例化该bean所依赖的bean。注意这里的dependon并不是指@Autowired这种依赖注入,而是大概这种方式

    <bean id="cat" class="com.lyc.cn.day08.Cat" p:name="美美" depends-on="dog"/>
    <bean id="helloApi" class="com.feng.spring.chapter2.helloworld.HelloApi">
    </bean>
    <bean id="decorator"  
        class="cn.javass.spring.chapter3.bean.HelloApiDecorator"  
        depends-on="helloApi">  
        <property name="helloApi"><ref bean="helloApi"/></property>  
    </bean>  

      同样的上面说的mergedBeanDefinition也不是指两个类之间的继承关系,而是这种通过配置文件配出来的两个bean的关系

    <bean id="parentBean" abstract="true">
            <property name="name" value="我是父亲"/>
        </bean>
        <bean id="sunBean" class="com.lyc.cn.day08.SunBean" parent="parentBean">
            <property name="age" value="18"/>
        </bean>

      接下来就是正式的实例化过程了

    4 AbstractAutowireCapableBeanFactory.createBean

    第一部分 准备工作

      if (logger.isDebugEnabled()) {
                logger.debug("Creating instance of bean '" + beanName + "'");
            }
            RootBeanDefinition mbdToUse = mbd;
    
            // Make sure bean class is actually resolved at this point, and
            // clone the bean definition in case of a dynamically resolved Class
            // which cannot be stored in the shared merged bean definition.
            Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
            if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
                mbdToUse = new RootBeanDefinition(mbd);
                mbdToUse.setBeanClass(resolvedClass);
            }
    
            // Prepare method overrides.
            try {
                mbdToUse.prepareMethodOverrides();
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                        beanName, "Validation of method overrides failed", ex);
            }
    
            try {
                // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
                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);
            }

      特别注意,// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. 大多数情况下Spring的动态代理并不是在这里完成的,除非在配置文件里显式的配了

    TargetSources,才会走到这里

    第二部分 开始实例化

     AbstractAutowireCapableBeanFactory.doCreateBean 

    // Instantiate the bean.
            BeanWrapper instanceWrapper = null;
            if (mbd.isSingleton()) {
                instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
            }
            if (instanceWrapper == null) {
                instanceWrapper = createBeanInstance(beanName, mbd, args);
            }

      真正进行实例化的代码就在 createBeanInstance 里,

      beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent); 对于绝大部分bean来说都是通过反射,利用class拿到构造方法,再用构造方法实例化对象,这里不再展开。

      回到doCreateBean继续分析

    缓存需要依赖注入的元信息

    // Allow post-processors to modify the merged bean definition.
            synchronized (mbd.postProcessingLock) {
                if (!mbd.postProcessed) {
                    try {
                        applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                    }
                    catch (Throwable ex) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "Post-processing of merged bean definition failed", ex);
                    }
                    mbd.postProcessed = true;
                }
            }

      applyMergedBeanDefinitionPostProcessors 的是就是这样的,那么  MergedBeanDefinitionPostProcessor的实现类有哪些呢?还真有一个比较有名的AutowiredAnnotationBeanPostProcessor。AutowiredAnnotationBeanPostProcessor是能够处理@Autowired和@Value这样的注解的。这也和之前介绍BeanPostProcessor里提到的呼应起来了,BeanPostProcessor有两个最特别的子类

      1  InstantiationAwareBeanPostProcessor

      2  MergedBeanDefinitionPostProcessor

    protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof MergedBeanDefinitionPostProcessor) {
                    MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
                    bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
                }
            }
        }

      我们来看看 AutowiredAnnotationBeanPostProcessor的 postProcessMergedBeanDefinition干了啥。

    @Override
        public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
            if (beanType != null) {
                InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
                metadata.checkConfigMembers(beanDefinition);
            }
        }
    private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
            // Fall back to class name as cache key, for backwards compatibility with custom callers.
            String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
            // Quick check on the concurrent map first, with minimal locking.
            InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
            if (InjectionMetadata.needsRefresh(metadata, clazz)) {
                synchronized (this.injectionMetadataCache) {
                    metadata = this.injectionMetadataCache.get(cacheKey);
                    if (InjectionMetadata.needsRefresh(metadata, clazz)) {
                        if (metadata != null) {
                            metadata.clear(pvs);
                        }
                        try {
                            metadata = buildAutowiringMetadata(clazz);
                            this.injectionMetadataCache.put(cacheKey, metadata);
                        }
    findAutowiringMetadata方法是很长的,这里只截取一段代码看看意思。
    buildAutowiringMetadata构造出来一个要注入的元数据对象,同时缓存在 injectionMetadataCache里面,缓存的key就是
    String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
    InjectionMetadata 是什么呢,就是一个对象里哪个属性是需要注入的(其他的由Spring管理的对象,而不是基本类型)。
    这些缓存信息AutowiredAnnotationBeanPostProcessor在后续代码执行中会用到的。

      再次回到doCreateBean继续分析

    解决循环依赖的

    // Eagerly cache singletons to be able to resolve circular references
            // even when triggered by lifecycle interfaces like BeanFactoryAware.
            boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                    isSingletonCurrentlyInCreation(beanName));
            if (earlySingletonExposure) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Eagerly caching bean '" + beanName +
                            "' to allow for resolving potential circular references");
                }
                addSingletonFactory(beanName, new ObjectFactory<Object>() {
                    @Override
                    public Object getObject() throws BeansException {
                        return getEarlyBeanReference(beanName, mbd, bean);
                    }
                });
            }

      这部分就是解决循环依赖的关键点,把一个实例化好了的bean放进三级缓存里。

    属性注入及初始化

      最重要的两个方法,populateBean和initializeBean

      populateBean是解决一个bean属性注入的。

      initializeBean是调用初始化方法的,比如@PostConstruct,配置文件里的init-method,和实现了InitializingBean接口的接口方法

    Object exposedObject = bean;
            try {
                populateBean(beanName, mbd, instanceWrapper);
                if (exposedObject != null) {
                    exposedObject = initializeBean(beanName, exposedObject, mbd);
                }
            }
            catch (Throwable ex) {
                if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                    throw (BeanCreationException) ex;
                }
                else {
                    throw new BeanCreationException(
                            mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
                }
            }

    分析下populateBean

        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
                    mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
                MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
    
                // Add property values based on autowire by name if applicable.
                if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
                    autowireByName(beanName, mbd, bw, newPvs);
                }
    
                // Add property values based on autowire by type if applicable.
                if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
                    autowireByType(beanName, mbd, bw, newPvs);
                }
    
                pvs = newPvs;
            }
         //上面的代码现在几乎不会走到,都是为了兼容老代码的,而且像@Autowired等注解也不走到里面
            boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
            boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
    
            if (hasInstAwareBpps || needsDepCheck) {
                PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                if (hasInstAwareBpps) {
                    for (BeanPostProcessor bp : getBeanPostProcessors()) {//循环遍历每一个beanPostProcessor调用他们的postProcessPropertyValues
                        if (bp instanceof InstantiationAwareBeanPostProcessor) {
                            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                            pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                            if (pvs == null) {
                                return;
                            }
                        }
                    }
                }

      不妨我们还是以AutowiredAnnotationBeanPostProcessor的 方法来举例

    public PropertyValues postProcessPropertyValues(
                PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
    
            InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
            try {
                metadata.inject(bean, beanName, pvs);
            }
            catch (BeanCreationException ex) {
                throw ex;
            }
            catch (Throwable ex) {
                throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
            }
            return pvs;
        }

    之前在 缓存需要依赖注入的元信息 这个小节交代过了, 实例化后会处理一个bean中的标签@Autowired并缓存起来。

    现在就可以直接用了

    拿到 InjectionMetadata metadata 后就调用  inject。

    对于autowired来说他对应的 方法是这样的

    @Override
            protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
                Field field = (Field) this.member;
                Object value;
                if (this.cached) {
                    value = resolvedCachedArgument(beanName, this.cachedFieldValue);
                }
                else {
                    DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
                    desc.setContainingClass(bean.getClass());
                    Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
                    TypeConverter typeConverter = beanFactory.getTypeConverter();
                    try {
                        value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);//把依赖的值解析出来
                    }
                    catch (BeansException ex) {
                        throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
                    }
                    synchronized (this) {
                        if (!this.cached) {
                            if (value != null || this.required) {
                                this.cachedFieldValue = desc;
                                registerDependentBeans(beanName, autowiredBeanNames);
                                if (autowiredBeanNames.size() == 1) {
                                    String autowiredBeanName = autowiredBeanNames.iterator().next();
                                    if (beanFactory.containsBean(autowiredBeanName)) {
                                        if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
                                            this.cachedFieldValue = new ShortcutDependencyDescriptor(
                                                    desc, autowiredBeanName, field.getType());
                                        }
                                    }
                                }
                            }
                            else {
                                this.cachedFieldValue = null;
                            }
                            this.cached = true;
                        }
                    }
                }
                if (value != null) {
                    ReflectionUtils.makeAccessible(field);
                    field.set(bean, value);//反射方法直接塞进去
                }
            }

      再说明一下另一个常用的自动注入注解@Resource,也是在 populateBean 中生效的

      在CommonAnnotationBeanPostProcessor中方法 buildResourceMetadata中的代码段中

    else if (field.isAnnotationPresent(Resource.class)) {
                            if (Modifier.isStatic(field.getModifiers())) {
                                throw new IllegalStateException("@Resource annotation is not supported on static fields");
                            }
                            if (!ignoredResourceTypes.contains(field.getType().getName())) {
                                currElements.add(new ResourceElement(field, field, null));
                            }
                        }

      如果一个字段头顶有@Resource会保存起来,等待后续处理

    上面是处理自动注入其他Bean的逻辑,最后还会执行一下属性静态值的注入,所谓的静态值就是配置文件里明确配了的值,这部分值会在装在BeanDefinition的时候就缓存在BD中

       applyPropertyValues(beanName, mbd, bw, pvs); 这部分就不详细说了。

    initializeBean

      到了执行初始化方法的时候了,这里说的初始化有三种,@PostConstruct,bean实现了initializingBean接口,和配置了init-method方法,这三种情况的执行。

      先看代码

    protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
            if (System.getSecurityManager() != null) {
                AccessController.doPrivileged(new PrivilegedAction<Object>() {
                    @Override
                    public Object run() {
                        invokeAwareMethods(beanName, bean);
                        return null;
                    }
                }, getAccessControlContext());
            }
            else {
                invokeAwareMethods(beanName, bean);
            }
    
            Object wrappedBean = bean;
            if (mbd == null || !mbd.isSynthetic()) {
                wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);//就在这里执行的@PostConstruct
            }
    
            try {
                invokeInitMethods(beanName, wrappedBean, mbd);//先initializingBean接口,而后才是init-method方法
    }
    catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);//大多数后置处理器都是直接return原bean } return wrappedBean; }
    调用applyBeanPostProcessorsBeforeInitialization过程中会调用InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization
    InitDestroyAnnotationBeanPostProcessor实现了接口 MergedBeanDefinitionPostProcessor 所以呢?在一个Bean实例化成一个空对象的时候,首先就执行过一次
    MergedBeanDefinitionPostProcessor的 postProcessMergedBeanDefinition 对元数据进行了缓存,此时就正好拿出来直接使用了
    @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
            try {
                metadata.invokeInitMethods(bean, beanName);
            }
            catch (InvocationTargetException ex) {
                throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
            }
            catch (Throwable ex) {
                throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
            }
            return bean;
        }

      最终调用 

    private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
            final boolean debug = logger.isDebugEnabled();
            LinkedList<LifecycleElement> initMethods = new LinkedList<LifecycleElement>();
            LinkedList<LifecycleElement> destroyMethods = new LinkedList<LifecycleElement>();
            Class<?> targetClass = clazz;
    
            do {
                final LinkedList<LifecycleElement> currInitMethods = new LinkedList<LifecycleElement>();
                final LinkedList<LifecycleElement> currDestroyMethods = new LinkedList<LifecycleElement>();
    
                ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback() {
                    @Override
                    public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
                        if (initAnnotationType != null) {
                            if (method.getAnnotation(initAnnotationType) != null) {
                                LifecycleElement element = new LifecycleElement(method);
                                currInitMethods.add(element);
                                if (debug) {
                                    logger.debug("Found init method on class [" + clazz.getName() + "]: " + method);
                                }
                            }
                        }
    initAnnotationType是在子类中赋值的,
    public CommonAnnotationBeanPostProcessor() {
            setOrder(Ordered.LOWEST_PRECEDENCE - 3);
            setInitAnnotationType(PostConstruct.class);
            setDestroyAnnotationType(PreDestroy.class);
            ignoreResourceType("javax.xml.ws.WebServiceContext");
        }

    所以,处理PostConstruct的就是CommonAnnotationBeanPostProcessor。并且面试中常问的初始化顺序问题通过源码也能够知道了。

    applyBeanPostProcessorsBeforeInitialization先执行,然后 invokeInitMethods才执行。所以PostConstruct最早执行。
    <bean id="helloApi" class="com.feng.spring.chapter2.helloworld.HelloApi">
    </bean>
    <bean id="decorator"  
        class="cn.javass.spring.chapter3.bean.HelloApiDecorator"  
        depends-on="helloApi">  
        <property name="helloApi"><ref bean="helloApi"/></property>  
    </bean>  
  • 相关阅读:
    如何使用Doxygen生成keil工程的代码文档 (how to use doxygen properly with keil)
    使用matlab画相交的平面
    转载:关于循环异步操作 Promise 实现,ES7 的 await 和 async
    小众软件:相见恨晚的 Windows 系统下的 cmd 的命令行替代者 Cmder(完美神器)
    Windows系统环境下Python脚本实现全局“划词复制”功能
    Ubuntu shell 命令行路径缩短
    shell查找数组是否有特定的值
    保存数据到文件
    左值与右值
    进程与线程的区别
  • 原文地址:https://www.cnblogs.com/juniorMa/p/13778249.html
Copyright © 2020-2023  润新知