博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring 中的 context
阅读量:6864 次
发布时间:2019-06-26

本文共 16132 字,大约阅读时间需要 53 分钟。

Spring 中的 context

BeanFactory

首先看下,官方在代码中给出的注释:

The root interface for accessing a Spring bean container.This is the basic client view of a bean container。

是接触所有Spring bean容器的根接口,这个接口被持有大量bean定义的对象实现。

从其接口中定义的方法即可看出,其为bean容器的真正含义。

ListableBeanFactory 继承了 BeanFactory,为其提供了枚举所有 beans 的方法:

ApplicationContext

而 ApplicationContext 类通过对该接口的扩展,提供了为application提供配置的扩展接口。

根据官方给出的注释,其总共功能有以下几点:

  1. 对应用的 component 的工厂方法;
  2. 一种通用的加载资源文件的方式;
  3. 对注册的监听器发布事件的能力;
  4. 解析message,支持国家化的能力。

这些能力主要通过继承各种接口获得,其自身接口主要扩展的重要方法主要有一个:

1@Nullable 2ApplicationContext getParent(); 复制代码

在 SpringBoot 中,context 有其继承体系:每个不同的 servlet 都有自己独立的 context,而整个 application 有一个根 context,这个 context 是所有 servlet 所共享的

所以此处提供了获得父 context 的能力。

ConfigurableApplicationContext

全部或者绝大多数 application 的context都会实现或者继承该接口。

扩展了一些配置 context 的方法,但是该接口中的方法仅仅在应用启动或者关闭时调用。

提供了set/get environment的方法;注册监听器的方法;当然还有最重要的 refresh 方法。

1/**  2 * Load or refresh the persistent representation of the configuration,  3 * which might an XML file, properties file, or relational database schema.  4 * 

As this is a startup method, it should destroy already created singletons 5 * if it fails, to avoid dangling resources. In other words, after invocation 6 * of that method, either all or no singletons at all should be instantiated. 7 * @throws BeansException if the bean factory could not be initialized 8 * @throws IllegalStateException if already initialized and multiple refresh 9 * attempts are not supported 10 */ 11void refresh() throws BeansException, IllegalStateException; 复制代码

从注释中我们可以看到该方法的作用:

加载或者刷新持久层的配置资源,比如 xml、property 或者数据库文件。

因为该方法在应用启动时调用,所以如果失败,则要销毁掉所有已经创建好的单例对象。

换句话说就是:一旦该方法被调用,要么创建好所有的单例对象,要么一个单例对象都不会创建

AbstractApplicationContext

对于 ConfigurableApplicationContext,该抽象类提供了大部分的模板实现方法。

这里重点看下 refresh 方法:

1@Override  2public void refresh() throws BeansException, IllegalStateException {
3   synchronized (this.startupShutdownMonitor) {
4      // Prepare this context for refreshing. 5      prepareRefresh(); 6 7      // Tell the subclass to refresh the internal bean factory. 8      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 9 10      // Prepare the bean factory for use in this context. 11      prepareBeanFactory(beanFactory); 12 13      try {
14         // Allows post-processing of the bean factory in context subclasses. 15         postProcessBeanFactory(beanFactory); 16 17         // Invoke factory processors registered as beans in the context. 18         invokeBeanFactoryPostProcessors(beanFactory); 19 20         // Register bean processors that intercept bean creation. 21         registerBeanPostProcessors(beanFactory); 22 23         // Initialize message source for this context. 24         initMessageSource(); 25 26         // Initialize event multicaster for this context. 27         initApplicationEventMulticaster(); 28 29         // Initialize other special beans in specific context subclasses. 30         onRefresh(); 31 32         // Check for listener beans and register them. 33         registerListeners(); 34 35         // Instantiate all remaining (non-lazy-init) singletons. 36         finishBeanFactoryInitialization(beanFactory); 37 38         // Last step: publish corresponding event. 39         finishRefresh(); 40      } 41 42      catch (BeansException ex) {
43         if (logger.isWarnEnabled()) {
44            logger.warn("Exception encountered during context initialization - " + 45                  "cancelling refresh attempt: " + ex); 46         } 47 48         // Destroy already created singletons to avoid dangling resources. 49         destroyBeans(); 50 51         // Reset 'active' flag. 52         cancelRefresh(ex); 53 54         // Propagate exception to caller. 55         throw ex; 56      } 57 58      finally {
59         // Reset common introspection caches in Spring's core, since we 60         // might not ever need metadata for singleton beans anymore... 61         resetCommonCaches(); 62      } 63   } 复制代码

该方法比较长,但是注释还是比较详细的,我们可以逐块分解的看:

先看第5行(以下提到具体的行数均指的是 refresh 方法中的)中的prepareRefresh:

1protected void prepareRefresh() {
2   // 设置一些容器 active flag 标志位 3   this.startupDate = System.currentTimeMillis(); 4   this.closed.set(false); 5   this.active.set(true); 6 7   // 初始化一些 environment 中的占位符属性 8   initPropertySources(); 9 10   // 校验一些标记为 required 的必要属性 11   getEnvironment().validateRequiredProperties(); 12 13   // 存储“准备刷新”的一些监听器. 14   if (this.earlyApplicationListeners == null) {
15      this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners); 16   } 17   else {
18      // Reset local application listeners to pre-refresh state. 19      this.applicationListeners.clear(); 20      this.applicationListeners.addAll(this.earlyApplicationListeners); 21   } 22 23   // 存储事件 24   this.earlyApplicationEvents = new LinkedHashSet<>(); 25} 复制代码

继续看第8行的代码 obtainFreshBeanFactory 发生了什么:

1protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
2   refreshBeanFactory(); 3   return getBeanFactory(); 4} 复制代码

这里使用了模板方法,refreshBeanFactory 的实现留给子类,官方给出的注释是:

1/** 2 * 子类必须实现该方法来执行实际的加载工作。 3 */ 4protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException; 复制代码

getBeanFactory 方法的实现也留给子类,官方的注释是:

1/** 2 * 子类在这里必须返回它内部的bean factory.  3 * 这个bean factory 应该实现高效的查询工作,这样重复调用时才不会造成性能损失. 4 * 注意: 5 * 子类在返回 bean factory 之前必须检查 context 是否属于 active 状态;如果处于 close 状态,则不能获取该对象。 6 */ 7@Override 8public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException; 复制代码

第 11 行,prepareBeanFactory 方法:

对于一些 context 的特征给出了配置,比如加载器、post-processor等。

1protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
2   //设置加载器 3   beanFactory.setBeanClassLoader(getClassLoader()); 4   //设置 Spring EL 解析器 5   beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); 6   //设置用于注册 PropertyEditor 的注册机 7   beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); 8 9   // Configure the bean factory with context callbacks. 10   // 设置一些用于 bean 后期处理的 processor 11   beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); 12   // 忽略一些依赖接口 13   beanFactory.ignoreDependencyInterface(EnvironmentAware.class); 14   beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); 15   beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); 16   beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); 17   beanFactory.ignoreDependencyInterface(MessageSourceAware.class); 18   beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); 19 20   // BeanFactory interface not registered as resolvable type in a plain factory. 21   // MessageSource registered (and found for autowiring) as a bean. 22   // 注册具有相应自动装配值得依赖类型 23   beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); 24   beanFactory.registerResolvableDependency(ResourceLoader.class, this); 25   beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); 26   beanFactory.registerResolvableDependency(ApplicationContext.class, this); 27 28   // 注册该监听器用于检测监听器 bean 29   beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); 30 31   // Detect a LoadTimeWeaver and prepare for weaving, if found. 32   if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
33      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); 34      // Set a temporary ClassLoader for type matching. 35      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); 36   } 37 38   // 注册默认的 environment beans. 39   if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
40      beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); 41   } 42   if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
43      beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); 44   } 45   if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
46      beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment()); 47   } 48} 复制代码

第15行 postProcessBeanFactory 方法:

1protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
2} 复制代码

也是一个模板方法,官方给出的注释是:

context 内部的 bean factory 初始化后,在此处进行一些修改。此时所有的bean定义都被加载,但是还没有任何一个bean被实例化。

第 18 行invokeBeanFactoryPostProcessors方法:

1protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
2   PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); 3 4   // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime 5   // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor) 6   if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
7      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); 8      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); 9   } 10} 复制代码

此方法的作用在于:实例化所有的bean 之前,实例化并调用一些 context 内部持有的 BeanFactoryPostProcessor。

第21行registerBeanPostProcessors方法:

1protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
2   PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this); 3} 复制代码

注册所有的 bean 后期处理类。

第24行 initMessageSource 方法:

1protected void initMessageSource() {
2   ConfigurableListableBeanFactory beanFactory = getBeanFactory(); 3   if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
4      this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class); 5      // Make MessageSource aware of parent MessageSource. 6      if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
7         HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource; 8         if (hms.getParentMessageSource() == null) {
9            // Only set parent context as parent MessageSource if no parent MessageSource 10            // registered already. 11            hms.setParentMessageSource(getInternalParentMessageSource()); 12         } 13      } 14      if (logger.isTraceEnabled()) {
15         logger.trace("Using MessageSource [" + this.messageSource + "]"); 16      } 17   } 18   else {
19      // Use empty MessageSource to be able to accept getMessage calls. 20      DelegatingMessageSource dms = new DelegatingMessageSource(); 21      dms.setParentMessageSource(getInternalParentMessageSource()); 22      this.messageSource = dms; 23      beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource); 24      if (logger.isTraceEnabled()) {
25         logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]"); 26      } 27   } 28} 复制代码

该方法进行了两方面的处理:

如果此 context中的 beanFactory 有 MessageSource 属性,则直接获取其值,并将其父MessageSource 设置到此context 的父context中;

如果此 context 中的 beanFactory 没有 MessageSource 属性,则直接使用 parent context中的 MessageSource。

第27行initApplicationEventMulticaster:

1protected void initApplicationEventMulticaster() {
2   ConfigurableListableBeanFactory beanFactory = getBeanFactory(); 3   if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
4      this.applicationEventMulticaster = 5            beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class); 6   //去掉日志打印 7   else {
8      this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); 9      beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster); 10      //去掉日志打印 11      } 12   } 13} 复制代码

此方法初始化 ApplicationEventMulticaster 广播器。

如果本地 context中有该属性,则直接获取值,如果没有则构造一个默认的SimpleApplicationEventMulticaster。

第30行 onRefresh 方法:

1protected void onRefresh() throws BeansException {
2   // For subclasses: do nothing by default. 3} 复制代码

又是一个模板方法,留待子类去实现。

主要是增加一些特定context 的 refresh 工作,在一些特殊的 bean 初始化时调用,该调用在任何单例对象实例化之前。

第33行registerListeners,检出并注册所有实现了ApplicationListener的监听器,如果此时有 event,则分发之。

1protected void registerListeners() {
2   // Register statically specified listeners first. 3   for (ApplicationListener
 listener : getApplicationListeners()) {
4      getApplicationEventMulticaster().addApplicationListener(listener); 5   } 6 7   // Do not initialize FactoryBeans here: We need to leave all regular beans 8   // uninitialized to let post-processors apply to them! 9   String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); 10   for (String listenerBeanName : listenerBeanNames) {
11      getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); 12   } 13 14   // Publish early application events now that we finally have a multicaster... 15   Set
 earlyEventsToProcess = this.earlyApplicationEvents; 16   this.earlyApplicationEvents = null; 17   if (earlyEventsToProcess != null) {
18      for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
19         getApplicationEventMulticaster().multicastEvent(earlyEvent); 20      } 21   } 22} 复制代码

第36行finishBeanFactoryInitialization方法:

完成此 context 中所有 factory bean 的初始化工作,实例化剩下的非惰性加载单例对象

1protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
2   // Initialize conversion service for this context. 3   if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && 4         beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
5      beanFactory.setConversionService( 6            beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); 7   } 8 9   // Register a default embedded value resolver if no bean post-processor 10   // (such as a PropertyPlaceholderConfigurer bean) registered any before: 11   // at this point, primarily for resolution in annotation attribute values. 12   if (!beanFactory.hasEmbeddedValueResolver()) {
13      beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); 14   } 15 16   // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early. 17   String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); 18   for (String weaverAwareName : weaverAwareNames) {
19      getBean(weaverAwareName); 20   } 21 22   // Stop using the temporary ClassLoader for type matching. 23   beanFactory.setTempClassLoader(null); 24 25   // Allow for caching all bean definition metadata, not expecting further changes. 26   beanFactory.freezeConfiguration(); 27 28   // Instantiate all remaining (non-lazy-init) singletons. 29   beanFactory.preInstantiateSingletons(); 30} 复制代码

重点放在下面两行上:

1// Allow for caching all bean definition metadata, not expecting further changes. 2beanFactory.freezeConfiguration(); 3 4// Instantiate all remaining (non-lazy-init) singletons. 5beanFactory.preInstantiateSingletons(); 复制代码

第一步 freeze 所有的 bean定义数据,该定义不能被更改;

第二步 开始真正实例化所有的单例。

第39行finishRefresh方法:

1protected void finishRefresh() {
2   // Clear context-level resource caches (such as ASM metadata from scanning). 3   clearResourceCaches(); 4 5   // Initialize lifecycle processor for this context. 6   initLifecycleProcessor(); 7 8   // Propagate refresh to lifecycle processor first. 9   getLifecycleProcessor().onRefresh(); 10 11   // Publish the final event. 12   publishEvent(new ContextRefreshedEvent(this)); 13 14   // Participate in LiveBeansView MBean, if active. 15   LiveBeansView.registerApplicationContext(this); 16} 复制代码

此时正式宣告完成 context 的refresh 工作,调用 LifecycleProcessor 的 onRefresh 方法,之后发布 ContextRefreshEvent 事件。

总结

此文对 Spring 中的几个重要的 context 进行了分析,尤其是对 AbstractApplicationContext 的主要脉络进行了梳理。

转载于:https://juejin.im/post/5cd182d36fb9a03222793435

你可能感兴趣的文章
BA 的岗位要求3
查看>>
基于Hyper-V3.0搭建XenDesktop7之九 部署虚拟应用之模板准备
查看>>
JS如何捆绑TypeScript声明文件
查看>>
samba服务配置
查看>>
我的友情链接
查看>>
MyBatis之ResultMap标签
查看>>
[转]WinXP、Win7脚本自动加域及用户资料迁移
查看>>
使用链路聚合进行负载分担
查看>>
NumPy之array
查看>>
ado 设置过滤
查看>>
微软私有云POC部署文档
查看>>
云计算
查看>>
mysql中的主从复制slave-skip-errors参数使用方法
查看>>
永久关闭wps热点新闻的办法
查看>>
飞信机器人安装
查看>>
修改一个字段中的部分内容
查看>>
kubernetes-1.11.0集群部署之master集群 (二)
查看>>
工作笔记--关于服务出问题时如何处理的流程
查看>>
Nginx常见的错误及解决方法
查看>>
springMVC入门配置及helloworld实例
查看>>