• SpringIoC之Bean生命周期源码主要流程解析


    生成BeanDefinition

    Spring启动的时候会进行扫描,会先调用
    org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#scanCandidateComponents(String basePackage) 扫描某个包路径,并得到BeanDefinition的Set集合
    spring扫描底层实现

    1. 首先,通过ResourcePatternResolver获得指定包路径下的所有 .class 文件(Spring源码中将
      此文件包装成了Resource对象)
    2. 遍历每个Resource对象
    3. 利用MetadataReaderFactory解析Resource对象得到MetadataReader(在Spring源码中
      MetadataReaderFactory具体的实现类为CachingMetadataReaderFactory,
      MetadataReader的具体实现类为SimpleMetadataReader)
    4. 利用MetadataReader进行excludeFilters和includeFilters,以及条件注解@Conditional的筛选
      (条件注解并不能理解:某个类上是否存在@Conditional注解,如果存在则调用注解中所指定的类的match方法进行匹配,匹配成功则通过筛选,匹配失败则pass掉。)
    5. 筛选通过后,基于metadataReader生成ScannedGenericBeanDefinition
    6. 再基于metadataReader判断是不是对应的类是不是接口或抽象类
    7. 如果筛选通过,那么就表示扫描到了一个Bean,将ScannedGenericBeanDefinition加入结果集
      metadataReader表示类的元数据读取器

    主要包含了一个AnnotationMetadata,功能有

    1. 获取类的名字
    2. 获取父类的名字
    3. 获取所实现的所有接口名
    4. 获取所有内部类的名字
    5. 判断是不是抽象类
    6. 判断是不是接口
    7. 判断是不是一个注解
    8. 获取拥有某个注解的方法集合
    9. 获取类上添加的所有注解信息
    10. 获取类上添加的所有注解类型集合
      值得注意的是,CachingMetadataReaderFactory解析某个.class文件得到MetadataReader对象是利用的ASM技术,并没有加载这个类到JVM。并且,最终得到ScannedGenericBeanDefinition对象,beanClass属性存储的是当前类的名字,而不是class对象。(beanClass属性的类型是Object,它即可以存储类的名字,也可以存储class对象)
      最后,上面是说的通过扫描得到BeanDefinition对象,我们还可以通过直接定义BeanDefinition,或解析spring.xml文件的,或者@Bean注解得到BeanDefinition对象

    合并BeanDefinition

    通过扫描得到所有BeanDefinition之后,就可以根据BeanDefinition创建Bean对象了,但是在
    Spring中支持父子BeanDefinition,和Java父子类类似,但是完全不是一回事。
    父子BeanDefinition实际用的比较少,使用是这样的,比如:

    <bean id="parent" class="com.zhouyu.service.Parent" scope="prototype"/>
    <bean id="child" class="com.zhouyu.service.Child"/>
    
    • 1
    • 2

    这么定义的情况下,child是单例Bean。

    <bean id="parent" class="com.zhouyu.service.Parent" scope="prototype"/>
    <bean id="child" class="com.zhouyu.service.Child" parent="parent"/>
    
    • 1
    • 2

    但是这么定义的情况下,child就是原型Bean了。
    因为child的父BeanDefinition是parent,所以会继承parent上所定义的scope属性。
    而在根据child来生成Bean对象之前,需要进行BeanDefinition的合并,得到完整的child的BeanDefinition。

    加载类

    BeanDefinition合并之后,就可以去创建Bean对象了,而创建Bean就必须实例化对象,而实例化就必须先加载当前BeanDefinition所对应的class,在AbstractAutowireCapableBeanFactory类的
    createBean()方法中,一开始就会调用:

    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    
    • 1

    这行代码就是去加载类,该方法是这么实现的:

    if (mbd.hasBeanClass()) {
        return mbd.getBeanClass();
    }
    if (System.getSecurityManager() != null) {
       return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>) ()>
       doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
    }else {
       return doResolveBeanClass(mbd, typesToMatch);
    }
    public boolean hasBeanClass() {
         return (this.beanClass instanceof Class);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    如果beanClass属性的类型是Class,那么就直接返回,如果不是,则会根据类名进行加载(doResolveBeanClass方法所做的事情)会利用BeanFactory所设置的类加载器来加载类,如果没有设置,则默认使用
    ClassUtils.getDefaultClassLoader()所返回的类加载器来加载。
    ClassUtils.getDefaultClassLoader()

    1. 优先返回当前线程中的ClassLoader
    2. 线程中类加载器为null的情况下,返回ClassUtils类的类加载器
    3. 如果ClassUtils类的类加载器为空,那么则表示是Bootstrap类加载器加载的ClassUtils类,那么则返回系统类加载器

    实例化前

    当前BeanDefinition对应的类成功加载后,就可以实例化对象了,但是在Spring中,实例化对象之前,Spring提供了一个扩展点,允许用户来控制是否在某个或某些Bean实例化之前做一些启动动作。这个扩展点叫

    InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()比如:

    @Component  
    public class CylBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    @Override  
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName)
    throws BeansException {
    if ("userService".equals(beanName)) {
          System.out.println("实例化前");
    }
       return null;
    }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    如上代码会导致,在userService这个Bean实例化前,会进行打印。

    @Component
    public class CylBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName)
    throws BeansException {
    if ("userService".equals(beanName)) {
       System.out.println("实例化前");
        return new UserService();
    }
      return null;
    }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    userService这个Bean,在实例化前会直接返回一个由我们所定义的UserService对象。由org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])中下面的代码可知:
    如果我们返回一个不为null的对象,表示不需要Spring来实例化了,并且后续的Spring依赖注入也不会进行了,会跳过一些步骤,直接执行初始化后这一步

    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);
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    实例化

    主要是推断构造函数去生成一个对象
    未完待续

  • 相关阅读:
    CNN--各层的介绍
    27、商户查询缓存(添加商户缓存)
    一文教你从Linux内核角度探秘JDK NIO文件读写本质(上)
    【车载以太网测试从入门到精通】——车载以太网休眠唤醒压力测试
    wx.canvasToTempFilePath生成图片保存到相册
    网络流总结 五万字符详解(56226字符)
    不同字符编码对比
    FastAdmin框架实现数据表的增删改查
    关于BenchMark/c++11计时器/Chrome:tracing 的一些笔记
    机器学习 -- 分类问题
  • 原文地址:https://blog.csdn.net/changyinling520/article/details/134278897