【俯瞰Spring】三、IoC容器初始化(上)

一、前言

从本节开始,会花较多篇幅去深入了解Spring IoC容器的初始化流程。整体串联的知识点会很多,包括IoC容器的实现、IoC容器的初始化、Bean定义扫描、Bean的生命周期、Spring的扩展机制BeanFactoryPostProcessorBeanPostProcessor,坚持住!


二、IoC容器创建及初始化

IoC容器的初始化,通常指的就是其 refresh()方法执行的整个流程,refresh()方法是Spring的最核心入口方法,不过在了解这个方法前,我们先看看IoC容器刷新之前做了什么前置工作?

结合源码来看,假设我们采用注解驱动式开发,写了MyIocClient这样一个启动类

@ComponentScan
public class MyIocClient {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyIocClient.class);
        
        // 关闭 context
        // context.close();
    }

}

没错,就上面一行代码就完成了ApplicationContext的创建及初始化;点进AnnotationConfigApplicationContext的构造方法`,总共就三步,看似很简单,但每一步做的事情都很重要。

2.1 第一步: 准备ApplicationContext

public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {

   private final AnnotatedBeanDefinitionReader reader;

   private final ClassPathBeanDefinitionScanner scanner;


   /**
    * Create a new AnnotationConfigApplicationContext that needs to be populated
    * through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
    */
   public AnnotationConfigApplicationContext() {
      /*
       * AnnotatedBeanDefinitionReader 的构造方法 向ioc容器导入几个注解驱动的基础BPP组件 以及 Bean定义的后置处理器
       * 见 AnnotatedBeanDefinitionReader 构造函数里面的 AnnotationConfigUtils.registerAnnotationConfigProcessors(BeanDefinitionRegistry, null) 方法:
       *
       * ConfigurationClassPostProcessor、
       * AutowiredAnnotationBeanPostProcessor、
       * RequiredAnnotationBeanPostProcessor、
       * CommonAnnotationBeanPostProcessor
       * EventListenerMethodProcessor
       */
      this.reader = new AnnotatedBeanDefinitionReader(this);

      // Bean定义扫描过滤配置
      this.scanner = new ClassPathBeanDefinitionScanner(this);
   }

   /**
    * Create a new AnnotationConfigApplicationContext with the given DefaultListableBeanFactory.
    * @param beanFactory the DefaultListableBeanFactory instance to use for this context
    */
   public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) {
      super(beanFactory);
      this.reader = new AnnotatedBeanDefinitionReader(this);
      this.scanner = new ClassPathBeanDefinitionScanner(this);
   }

   /**
    * Create a new AnnotationConfigApplicationContext, deriving bean definitions
    * from the given annotated classes and automatically refreshing the context.
    * @param annotatedClasses one or more annotated classes,
    * e.g. {@link Configuration @Configuration} classes
    */
   public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
      // 父类 GenericApplicationContext 的构造方法,创建了DefaultListableBeanFactory;
      // 无参构造函数里面通过 AnnotatedBeanDefinitionReader , 向Ioc容器导入了几个注解开发的基础BPP组件
      this();

      // 为启动类创建 beanDefinition 并注册
      register(annotatedClasses);

      refresh();
   }

}

一开始调用自身的无参构造方法,这里隐含一个知识点「Java类调用自身无参构造方法时会先触发父类无参构造」。点进其父类GenericApplicationContext无参构造,可以看到直接new了一个DefaultListableBeanFactory, 其就是一个标准的完成度很高的IoC容器实现,后面Ioc容器刷新过程中到到的BeanFactory都是这个一个东东

public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {

   private final DefaultListableBeanFactory beanFactory;

   /**
    * Create a new GenericApplicationContext.
    * @see #registerBeanDefinition
    * @see #refresh
    */
   public GenericApplicationContext() {
      // 这里就创建了 DefaultListableBeanFactory
      this.beanFactory = new DefaultListableBeanFactory();
   }
}

再退回到 AnnotationConfigApplicationContext无参构造, 可以看到无参构造里面new出了两个对象, 这两个对象也比较重要:

  • AnnotatedBeanDefinitionReader见名知意,就是在注解驱动开发中解析 BeanDefinition
  • ClassPathBeanDefinitionScanner 进行ClassPath下的 BeanDefinition 扫描及注册
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {

   private final AnnotatedBeanDefinitionReader reader;

   private final ClassPathBeanDefinitionScanner scanner;


   /**
    * Create a new AnnotationConfigApplicationContext that needs to be populated
    * through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
    */
   public AnnotationConfigApplicationContext() {
      /*
       * AnnotatedBeanDefinitionReader 的构造方法 向ioc容器导入几个注解驱动的基础BPP组件 以及 Bean定义的后置处理器
       * 见 AnnotatedBeanDefinitionReader 构造函数里面的 AnnotationConfigUtils.registerAnnotationConfigProcessors(BeanDefinitionRegistry, null) 方法:
       *
       * ConfigurationClassPostProcessor、
       * AutowiredAnnotationBeanPostProcessor、
       * RequiredAnnotationBeanPostProcessor、
       * CommonAnnotationBeanPostProcessor
       * EventListenerMethodProcessor
       */
      this.reader = new AnnotatedBeanDefinitionReader(this);

      // Bean定义扫描过滤配置
      this.scanner = new ClassPathBeanDefinitionScanner(this);
   }

}

这里有必要强调下,AnnotatedBeanDefinitionReader这家伙的构造方法不仅仅只是为了new一个对象出来,还顺带为IoC容器导入了几个组件,具体可分为以下几种

  • 导入修改Bean定义的BeanFacotroyPostProcess组件
    • ConfigurationClassPostProcessor: 用来处理 @Configuration 注解
  • 导入依赖注入的BeanPostProcess组件
    • AutowiredAnnotationBeanPostProcessor: 用来处理 @Autowired 注解
    • RequiredAnnotationBeanPostProcessor: 用来处理 @Required 注解
    • CommonAnnotationBeanPostProcessor: 用来处理 @Resource、@PostConstruct、@PreDestroy 注解
  • 导入Jpa组件
    • PersistenceAnnotationBeanPostProcessor
  • 导入Spring事件监听组件
    • EventListenerMethodProcessor
    • DefaultEventListenerFactory

导入组件的具体代码见 AnnotatedBeanDefinitionReader

public class AnnotationConfigUtils {

   /**
    * Register all relevant annotation post processors in the given registry.
    * @param registry the registry to operate on
    * @param source the configuration source element (already extracted)
    * that this registration was triggered from. May be {@code null}.
    * @return a Set of BeanDefinitionHolders, containing all bean definitions
    * that have actually been registered by this call
    */
   public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
         BeanDefinitionRegistry registry, Object source) {

      DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
      if (beanFactory != null) {
         if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
            beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
         }
         if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
            beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
         }
      }

      Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(8);


      if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
         RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
         def.setSource(source);
         // 重要: BeanDefinition 的后置处理器
         beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
      }

      if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
         RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
         def.setSource(source);
         beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
      }

      if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
         RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
         def.setSource(source);
         beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
      }

      // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
      if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
         // 重要: 处理 @Resource  @PostConstruct  @PreDestroy 注解的BPP
         RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
         def.setSource(source);
         beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
      }

      // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
      if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
         RootBeanDefinition def = new RootBeanDefinition();
         try {
            def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
                  AnnotationConfigUtils.class.getClassLoader()));
         }
         catch (ClassNotFoundException ex) {
            throw new IllegalStateException(
                  "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
         }
         def.setSource(source);
         beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
      }

      if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
         RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
         def.setSource(source);
         beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
      }

      //  EventListenerMethodProcessor.getEventListenerFactories() 这个方法会用到
      if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
         RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
         def.setSource(source);
         beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
      }

      return beanDefs;
   }

}

ClassPathBeanDefinitionScanner 这个对象的职责比较单一,就是为了后续扫描进行ClassPath下带有 @Componnent注解的类,进而解析注册 BeanDefinition; (注:@Service、@Repository、@Controller 这些注解其实都叠加了 @Componnent 注解,也是能被扫描到的)

至此,第一步就粗略过完了。一个this()方法就引出了这么一长串,Spring封装做得也真够了!

2.2 第二步: 注册启动类Bean定义

第二步就比较简单了, 直接为启动类创建Bean定义AnnotatedGenericBeanDefinition, 并完成注册。启动类啥业务逻辑都没有,为什么需要注册呢?其实注册的目前是为了做ClassPath下面的Bean定义扫描,IoC容器是需要我们告知从哪些路径开始扫描的。

还记得启动类上的 @ComponentScan 注解吗, 通过启动类这个载体,IoC容器知道了扫描的起点是什么,顺腾摸瓜最终就就能完成扫描。特别低,我们的启动类上@ComponentScan注解并未显示指定任何属性,Spring这时候的做法就是把启动类所在的包名,当做扫描的根起点。这个机制就能解释为什么往往会把启动类单独放在最外一层的包上面。

public class AnnotatedBeanDefinitionReader {

   private final BeanDefinitionRegistry registry;

   private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();

   private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();

   private ConditionEvaluator conditionEvaluator;

   /**
    * Register a bean from the given bean class, deriving its metadata from
    * class-declared annotations.
    * @param annotatedClass the class of the bean
    */
   @SuppressWarnings("unchecked")
   public void registerBean(Class<?> annotatedClass) {
      registerBean(annotatedClass, null, (Class<? extends Annotation>[]) null);
   }


   /**
    * Register a bean from the given bean class, deriving its metadata from
    * class-declared annotations.
    * @param annotatedClass the class of the bean
    * @param name an explicit name for the bean
    * @param qualifiers specific qualifier annotations to consider,
    * in addition to qualifiers at the bean class level
    */
   @SuppressWarnings("unchecked")
   public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) {
      AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
      if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
         return;
      }

      ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
      abd.setScope(scopeMetadata.getScopeName());
      String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
      // 解析 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));
            }
         }
      }

      BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
      definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
      // 导入bean定义
      BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
   }
}

2.3 第三步: 初始化Ioc容器

refresh()方法是Ioc容器初始化的起点,实现逻辑在抽象类 AbstractApplicationContext,整个方法细分为十二步,妥妥滴模板方法设计模式。后续会开文逐个步骤讲解,这里先混个脸熟,了解下IoC容器初始化的全貌;特别重要的两步是 invokeBeanFactoryPostProcessors(beanFactory)finishBeanFactoryInitialization(beanFactory);

public abstract class AbstractApplicationContext extends DefaultResourceLoader
      implements ConfigurableApplicationContext, DisposableBean {


   @Override
   public void refresh() throws BeansException, IllegalStateException {
      synchronized (this.startupShutdownMonitor) {
         // Prepare this context for refreshing.
         prepareRefresh();

         /*
          * 这里获取到的BeanFactory是 DefaultListableBeanFactory,
          * 它不是这里创建的, 而是在这之前的 GenericApplicationContext 的构造函数里面new出来的
          */
         // Tell the subclass to refresh the internal bean factory.
         ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

         /*
          * 对DefaultListableBeanFactory 做一些准备工作: 比如配置ClassLoader 、导入BPP组件
          */
         // Prepare the bean factory for use in this context.
         prepareBeanFactory(beanFactory);

         try {
            // Allows post-processing of the bean factory in context subclasses.
            postProcessBeanFactory(beanFactory);

            /**
             * 核心步骤:加载Bean定义;
             * 调用BeanFactoryPostProcessor,会触发getBean操作; 这里用到的两个BPP都是在 prepareBeanFactory() 阶段导入的
             */
            // Invoke factory processors registered as beans in the context.
            invokeBeanFactoryPostProcessors(beanFactory);

            /*
             * 注册bean的后置处理器
             */
            // 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();

            /**
             * 核心步骤:bean实例化、初始化
             */
            // Instantiate all remaining (non-lazy-init) singletons.
            finishBeanFactoryInitialization(beanFactory);

            // Last step: publish corresponding event.
            finishRefresh();
         }

         catch (BeansException ex) {
            if (logger.isWarnEnabled()) {
               logger.warn("Exception encountered during context initialization - " +
                     "cancelling refresh attempt: " + ex);
            }

            // Destroy already created singletons to avoid dangling resources.
            destroyBeans();

            // Reset 'active' flag.
            cancelRefresh(ex);

            // Propagate exception to caller.
            throw ex;
         }

         finally {
            // Reset common introspection caches in Spring's core, since we
            // might not ever need metadata for singleton beans anymore...
            resetCommonCaches();
         }
      }
   }


三、小结

  • Spring IoC容器创建及初始化分三步
    在这里插入图片描述

  • IoC容器初始化的前置准备工作分两块:

    • 创建 AnnotatedBeanDefinitionReader并导入系列组件

    • 创建并配置 ClassPathBeanDefinitionScanner后续用来进行ClassPath下的Bean定义扫描注册
      在这里插入图片描述

发布了27 篇原创文章 · 获赞 4 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/caiguoxiong0101/article/details/104720645