IOC容器加载过程及Bean的生命周期和后置处理器

SpringIOC 容器加载过程

第一步:实例化化容器:AnnotationConfigApplicationContext

@Configuration
@ComponentScan("cn.zhe")
public class MainStartTest {
    public static void main(String[] args) {
        // SpringIOC 出发点 加载Spring上下文
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainStartTest.class);
        HelloSpring bean = applicationContext.getBean(HelloSpring.class);
        bean.sayHello();
    }
}

构造函数

// 根据参数可知,可以传入多个Class,但这种情况及其少见
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
    /**
    * 调用无参构造函数
    * 主要分三步:
    *    a.调用父类构造函数
    *    b.本类构造函数 初始化注解模式下的 bean定义读取器 AnnotatedBeanDefinitionReader
    *    c.本类构造函数 初始化 classPath类型的 bean定义扫描器 AnnotatedBeanDefinitionScaner
    */
    this();
    /**
     * 注册配置类
     * 把传入的类进行注册,分为两种情况
     *     a. @Configuration的配置类
     *     b. 传入普通 Bean (基本不会这么做)
     *  Spring把配置类分为两种
     *     a. 带@Configuration注解的配置类称之为FULL配置类
     *     b. 不带@Configuration注解,是带有@Component,@Import,@ImportResouce,
     *        @Service, @ComponentScan等注解的配置类称之为Lite配置类
     */
    register(componentClasses);
    // 刷新IOC容器
    refresh();
}


this()方法分析开始

第二步:实例化工厂:DefaultListableBeanFactory

DefaultListableBeanFactory 就是我们所说的容器,里面放着beanDefinitionMap, beanDefinitionNames等

// 调用无参构造,会先调用父类GenericApplicationContext的构造函数
// 第一步调用父类构造函数,创建一个Bean工厂
public GenericApplicationContext() {
    /**
    * 调用父类的构造函数,为 ApplicationContext spring 上下文对象初始 beanFactory
    * 因为 DefaultListableBeanFactory 是最底层的实现,功能是最全的
    */
    this.beanFactory = new DefaultListableBeanFactory();
}

// 第二三步
 public class AnnotationConfigApplicationContext extends GenericApplicationContext 
     implements AnnotationConfigRegistry {
     // 注解bean定义读取器,主要作用是用来读取被注解的Bean
     private final AnnotatedBeanDefinitionReader reader;
     // 外部调用scan手动扫描的scanner对象,用处不大
     private final ClassPathBeanDefinitionScanner scanner;

     public AnnotationConfigApplicationContext() {
        /**
         * 初始化注解模式下的bean定义扫描器
         * 调用AnnotatedBeanDefinitionReader构造方法,传入的
         * 是this(AnnotationConfigApplicationContext)对象
         */
        this.reader = new AnnotatedBeanDefinitionReader(this);
        /**
        * 初始化classPath类型的bean定义扫描器
        * 使用场景极少,仅外部手动调用扫描使用,常规方式是不会用到scanner对象的
        * 此处扫描器仅用于自定义的扫描 applicationContext.scan();
        */
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }
 }

第三步:实例化 BeanDefinition 读取器 (AnnotatedBeanDefinitionReader)

主要就做了两件事情:

  • 注册内置 BeanPostProcessor
  • 注册内置相关核心的 BeanDefinition
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment {
   Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
   Assert.notNull(environment, "Environment must not be null");
   // 把ApplicationContext对象赋值给AnnotatedBeanDefinitionReader
   this.registry = registry;
   // 用户处理条件表达式计算 @Condition
   this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
   // 注册一些配置的后置处理器,并注册Spring内置的多个Bean
   AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}                               

关于registerAnnotationConfigProcessors(this.registry);方法内容较多,但大多相同的判断,注册 Spring 内置的多个 Bean,以ConfigurationClassPostProcesso为例:

/**
 * 为容器中注册解析配置类的后置处理器 ConfigurationClassPostProcessor
 * org.springframework.context.annotation.internalConfigurationAnnotationProcessor
 */
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
   RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
   def.setSource(source);
   beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}

/**
 * 这方法为BeanDefinition设置了一个Role,ROLE_INFRASTRUCTURE代表这是spring内部的,并非用户定义的
 * registry.registerBeanDefinition(beanName, definition);是一个接口方法,
 * 实现类是 DefaultListableBeanFactory
 *    核心工作就是
 *    a.this.beanDefinitionMap.put(beanName, beanDefinition);
 *      把beanName作为key,beanDefinition作为value,放到map里面
 *    b.beanDefinitionNames就是一个List<String>,这里就是把beanName放到List中去
 * DefaultListableBeanFactory就是我们所说的容器,里面放着beanDefinitionMap, beanDefinitionNames,
 *      beanDefinitionMap是一个hashMap,beanName作为Key,beanDefinition作为Value,
 *      beanDefinitionNames是一个集合,里面存放了beanName
 */
private static BeanDefinitionHolder registerPostProcessor(
    BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {

    definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    // 核心已在上方注释
    registry.registerBeanDefinition(beanName, definition);
    return new BeanDefinitionHolder(definition, beanName);
}

逻辑就是:

  1. 判断容器中是否已经存在了ConfigurationClassPostProcessorBean
  2. 如果不存在,就通过 RootBeanDefinition 的构造方法获得ConfigurationClassPostProcessor的BeanDefinition
  3. 执行registerPostProcessor()方法,其内部就是注册Bean(与其他 Bean 注册流程一致)

internalConfigurationAnnotationProcessor

ConfigurationClassPostProcessor 是 Spring 中极其重要的一个类,它实现 BeanDefinitionRegistryPostProcessor 接口,BeanDefinitionRegistryPostProcessor 接口又扩展了 BeanFactoryPostProcessor 接口,BeanFactoryPostProcessor 是 Spring 的扩展点之一

至此加载完以下扩展点(beanDefinition -> beanDefinitionMap)

第四步:创建 BeanDefinition 扫描器 (ClassPathBeanDefinitionScanner)

初始化 classPath 类型的 BeanDefinition 扫描器,使用场景极少,仅外部手动调用扫描使用,常规方式是不会用到 scanner 对象的此处扫描器仅用于自定义的扫描applicationContext.scan()

至此this()方法结束


register(annotatedClasses);分析开始

第五步:注册配置类为BeanDefinition (register(annotatedClasses);)

/**
 * 注册配置类
 * 把传入的类进行注册,分为两种情况
 *     a. @Configuration的配置类
 *     b. 传入普通 Bean (基本不会这么做)
 * Spring把配置类分为两种
 *     a. 带@Configuration注解的配置类称之为FULL配置类
 *     b. 不带@Configuration注解,是带有@Component,@Import,@ImportResouce,
 *        @Service, @ComponentScan等注解的配置类称之为Lite配置类
 */
register(componentClasses);

public void register(Class<?>... componentClasses) {
    this.reader.register(componentClasses);
}

private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
      @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
      @Nullable BeanDefinitionCustomizer[] customizers) {
   // AnnotatedGenericBeanDefinition可以理解为一种数据结构,是用来描述Bean的,这里的作用就是把传入
   // 的标记了注解的类转为AnnotatedGenericBeanDefinition数据结构,里面有一个getMetadata方法,可以拿到类上的注解
   AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
   // 判断是否需要跳过注解,spring中有一个@Condition注解,当不满足条件,这个bean就不会被解析
   if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
      return;
   }

   abd.setInstanceSupplier(supplier);
   // 解析bean的作用域,如果没有设置的话,默认为单例
   ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
   abd.setScope(scopeMetadata.getScopeName());
   // 获得beanName
   String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
   // 解析通用注解,填充到AnnotatedGenericBeanDefinition,
   // 解析的注解 Lazy,Primary,DependsOn,Role,Description
   AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
   if (qualifiers != null) {
      for (Class<? extends Annotation> qualifier : qualifiers) {
         if (Primary.class == qualifier) {
            abd.setPrimary(true);
         }
         else if (Lazy.class == qualifier) {
            abd.setLazyInit(true);
         }
         else {
            abd.addQualifier(new AutowireCandidateQualifier(qualifier));
       
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值