Loading

ApplicationContext体系

ApplicationContext是Spring容器针对应用层开放的接口。

相对于BeanFactory体系,仅仅起着容器的作用,需要借助AnnatatedBeanDefinitionReader手动注册类对象,或者ClassPathBeanDefinitionScanner扫描指定路径,才能完成Spring容器的初始化。

ApplicationContext体系直接将AnnatatedBeanDefinitionReaderClassPathBeanDefinitionScanner作为自己的成员变量,集成了读取依赖配置和注册BeanDefinition的功能。此外,还提供了许多增强的功能,比如触发BeanFactoryPostProcessor回调,自动实例化单例bean等。

ApplicationContext体系十分复杂,但是它的核心实现类只有AnnotationConfigApplicationContextAnnotationConfigServletWebServerApplicationContext。我们只需要重点学习这两个实现类,就能深刻理解ApplicationContext的实现原理。

1 AnnotationConfigApplicationContext

AnnotationConfigApplicationContext的核心成员变量:

  • beanFactoryDefaultListableBeanFactory对象,Spring IoC容器。
  • readerAnnotatedBeanDefinitionReader对象,用于将指定类对象注册成bean
  • scannerClassPathBeanDefiniionScanner对象,用于将指定路径下的类对象注册成bean
  • environment:运行时环境。
  • beanFactoryPostProcessorsBeanFactoryPostPr4ocessor缓存。

AnnotationConfigApplicationContext的基本使用:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();  
context.register(AppConfig.class);  
context.scan("applicationcontext");  
context.refresh();  
AppConfig bean = context.getBean(AppConfig.class);  
System.out.println(bean);

1.1 构造函数

使用默认无参构造函数,会初始化AnnotatedBeanDefinitionReaderClassPathBeanDefinitionScanner对象,用于读取依赖配置:

public AnnotationConfigApplicationContext() {  
   this.reader = new AnnotatedBeanDefinitionReader(this);  
   this.scanner = new ClassPathBeanDefinitionScanner(this);  
}

在父类GenericApplicationContext的默认无参构造函数中,会初始化beanFactory

public GenericApplicationContext() {  
   this.beanFactory = new DefaultListableBeanFactory();  
}

在父类AbstractApplicationContext的默认无参构造函数中,会初始化resourcePatternResolver

public AbstractApplicationContext() {  
   this.resourcePatternResolver = getResourcePatternResolver();  
}

1.2 register和scan

AnnotationConfigApplicationContext#register()会调用内部的AnnotatedBeanDefinitionReader对象的register()方法,读取指定类对象,封装成BeanDefinition,然后注册到BeanFactory中:

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

AnnotationConfigApplicationContext#scan()会调用内部的ClassPathBeanDefinitionScanner对象的scan()方法,扫描指定路径下的@Component类,封装成BeanDefinition,然后注册到BeanFactory中:

public void scan(String... basePackages) {
   this.scanner.scan(basePackages);
}

DefaultListableBeanFacoty一样,GenericApplicationContext也实现了BeanDefinitionRegistry接口,它会将BeanDefinition注册到内部持有的beanFactoryDefaultListableBeanFactory对象)中:

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)  
      throws BeanDefinitionStoreException {  
   this.beanFactory.registerBeanDefinition(beanName, beanDefinition);  
}

1.3 refresh

AbstractApplicationContext#refresh()方法会对容器进行一个初始化操作:

  1. 初始化标准上下文的基础配置:BeanFactoryPostProcessor等。
  2. 注册容器特定的BeanFactoryPostProcessor
  3. 触发BeanFactoryPostProcessor的回调。
  4. 注册BeanPostProcessor
  5. 初始化MessageSource
  6. 初始化ApplicationEventMulticaster
  7. 初始化容器特定的bean
  8. 注册listeners
  9. 实例化所有单例bean(non-lazy-init) 。
  10. 清除context-level资源缓存。
  11. 初始化LifecycleProcessor
  12. 触发LifecycleProcessor#onRefresh()方法。
  13. 发布ContextRefreshedEvent事件。
  14. 清除占用的资源。

AbstractApplicationContext#refresh()

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();  
  
      /*
      * 初始化标准applicationContext的基础配置:
      * 1、上下文的ClassLoader
      * 2、post-processor:ApplicationContextAwareProcessor、ApplicationListenerDetector等
      * 3、注册单例对象:environment、systemProperties、systemEnvironment、applicationStartup
      */
      prepareBeanFactory(beanFactory);  
  
      try {  
         // 不同子类会添加特定的BeanFactoryPostProcessor
         postProcessBeanFactory(beanFactory);  

         // 触发BeanFactoryPostProcessor的回调方法
         invokeBeanFactoryPostProcessors(beanFactory);  
  
         // 注册BeanPostProcessor
         registerBeanPostProcessors(beanFactory);  
  
         // 初始化MessageSource
         initMessageSource();  
  
         // 初始化ApplicationEventMulticaster
         initApplicationEventMulticaster();  
  
         // 不同子类会初始化特定的bean
         onRefresh();  
  
         // 注册ApplicationListener类型的bean为listeners
         registerListeners();  
  
         // 实例化所有单例bean (non-lazy-init) 
         finishBeanFactoryInitialization(beanFactory);  
  
         /*
         * 1、清除context-level资源缓存
         * 2、初始化LifecycleProcessor
         * 3、触发LifecycleProcessor的onRefresh()方法
         * 4、发布ContextRefreshedEvent事件
         */
         finishRefresh();  
      }  
  
      catch (BeansException ex) {  
         // 销毁已创建的所有单例对象,避免资源浪费
         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();  
      }  
   }  
}

1.4 getBean

AbstractApplicationContext#getBean()会交给内部的beanFactory去执行:

public Object getBean(String name) throws BeansException {  
   assertBeanFactoryActive();  
   return getBeanFactory().getBean(name);  
}

2 AnnotationConfigServletWebServerApplicationContext

AnnotationConfigServletWebServerApplicationContext的成员变量与AnnotationConfigApplicationContext差不多,只是多了web相关的信息:

  • servletContext
  • webServet
  • servletConfig

并且此时会缓存待注册的类对象和扫描路径,在refresh()方法中才会进行实际注册:

  • annotatedClasses:待注册类对象。
  • basePackages:待扫描路径。

AnnotationConfigServletWebServerApplicationContext的使用主要是在Spring Boot项目中,AnnotationConfigServletWebServerApplicationContext.Factory#create()

public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {  
   return (webApplicationType != WebApplicationType.SERVLET) ? null  
         : new AnnotationConfigServletWebServerApplicationContext();  
}

虽然经过了多层封装,但是接下来还是会依次调用以下方法进行容器初始化:

  1. register()scan():注册BeanDefinition
  2. refresh():初始化容器。

2.1 构造函数

使用默认无参构造函数,会初始化AnnotatedBeanDefinitionReaderClassPathBeanDefinitionScanner对象,用于读取依赖配置:

public AnnotationConfigServletWebServerApplicationContext() {  
   this.reader = new AnnotatedBeanDefinitionReader(this);  
   this.scanner = new ClassPathBeanDefinitionScanner(this);  
}

在父类GenericApplicationContext的默认无参构造函数中,会初始化beanFactory

public GenericApplicationContext() {  
   this.beanFactory = new DefaultListableBeanFactory();  
}

在父类AbstractApplicationContext的默认无参构造函数中,会初始化resourcePatternResolver

public AbstractApplicationContext() {  
   this.resourcePatternResolver = getResourcePatternResolver();  
}

2.2 register和scan

AnnotationConfigServletWebServerApplicationContext#register()方法会缓存待注册的类对象:

public final void register(Class<?>... annotatedClasses) {  
   this.annotatedClasses.addAll(Arrays.asList(annotatedClasses));  
}

AnnotationConfigServletWebServerApplicationContext#scan()方法会缓存待扫描的路径:

public final void scan(String... basePackages) {
   this.basePackages = basePackages;  
}

在后续refresh阶段的AnnotationConfigServletWebServerApplicationContext#postProcessBeanFactory()方法中,才会进行实际注册BeanDefinition

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {  
   super.postProcessBeanFactory(beanFactory);  
   if (this.basePackages != null && this.basePackages.length > 0) {  
      this.scanner.scan(this.basePackages);  
   }  
   if (!this.annotatedClasses.isEmpty()) {  
      this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));  
   }  
}

2.3 refresh

ServletWebServerApplicationContext#refresh()方法实际上会调用到AbstractApplicationContext#refresh()方法:

public final void refresh() throws BeansException, IllegalStateException {  
   try {  
      super.refresh();  
   }  
   catch (RuntimeException ex) {  
      WebServer webServer = this.webServer;  
      if (webServer != null) {  
         webServer.stop();  
      }  
      throw ex;  
   }  
}

需要注意的是,此时调用postProcessBeanFactory()方法时,会进行实际注册BeanDefinition操作。

2.4 getBean

AbstractApplicationContext#getBean()会交给内部的beanFactory去执行:

public Object getBean(String name) throws BeansException {  
   assertBeanFactoryActive();  
   return getBeanFactory().getBean(name);  
}
posted @ 2023-01-18 21:58  Xianuii  阅读(188)  评论(0编辑  收藏  举报