Spring 中的 context
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提供配置的扩展接口。
根据官方给出的注释,其总共功能有以下几点:
- 对应用的 component 的工厂方法;
- 一种通用的加载资源文件的方式;
- 对注册的监听器发布事件的能力;
- 解析message,支持国家化的能力。
这些能力主要通过继承各种接口获得,其自身接口主要扩展的重要方法主要有一个:
1@Nullable2ApplicationContext 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 * <p>As this is a startup method, it should destroy already created singletons5 * if it fails, to avoid dangling resources. In other words, after invocation6 * of that method, either all or no singletons at all should be instantiated.7 * @throws BeansException if the bean factory could not be initialized8 * @throws IllegalStateException if already initialized and multiple refresh9 * attempts are not supported10 */11void refresh() throws BeansException, IllegalStateException;
从注释中我们可以看到该方法的作用:
加载或者刷新持久层的配置资源,比如 xml、property 或者数据库文件。
因为该方法在应用启动时调用,所以如果失败,则要销毁掉所有已经创建好的单例对象。
换句话说就是:一旦该方法被调用,要么创建好所有的单例对象,要么一个单例对象都不会创建。
AbstractApplicationContext
对于 ConfigurableApplicationContext,该抽象类提供了大部分的模板实现方法。
这里重点看下 refresh 方法:
1@Override2public void refresh() throws BeansException, IllegalStateException{3 synchronized (this.startupShutdownMonitor) {4 // Prepare this context for refreshing.5 prepareRefresh();67 // Tell the subclass to refresh the internal bean factory.8 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();910 // Prepare the bean factory for use in this context.11 prepareBeanFactory(beanFactory);1213 try {14 // Allows post-processing of the bean factory in context subclasses.15 postProcessBeanFactory(beanFactory);1617 // Invoke factory processors registered as beans in the context.18 invokeBeanFactoryPostProcessors(beanFactory);1920 // Register bean processors that intercept bean creation.21 registerBeanPostProcessors(beanFactory);2223 // Initialize message source for this context.24 initMessageSource();2526 // Initialize event multicaster for this context.27 initApplicationEventMulticaster();2829 // Initialize other special beans in specific context subclasses.30 onRefresh();3132 // Check for listener beans and register them.33 registerListeners();3435 // Instantiate all remaining (non-lazy-init) singletons.36 finishBeanFactoryInitialization(beanFactory);3738 // Last step: publish corresponding event.39 finishRefresh();40 }4142 catch (BeansException ex) {43 if (logger.isWarnEnabled()) {44 logger.warn("Exception encountered during context initialization - " +45 "cancelling refresh attempt: " + ex);46 }4748 // Destroy already created singletons to avoid dangling resources.49 destroyBeans();5051 // Reset 'active' flag.52 cancelRefresh(ex);5354 // Propagate exception to caller.55 throw ex;56 }5758 finally {59 // Reset common introspection caches in Spring's core, since we60 // 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);67 // 初始化一些 environment 中的占位符属性8 initPropertySources();910 // 校验一些标记为 required 的必要属性11 getEnvironment().validateRequiredProperties();1213 // 存储“准备刷新”的一些监听器.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 }2223 // 存储事件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@Override8public 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()));89 // Configure the bean factory with context callbacks.10 // 设置一些用于 bean 后期处理的 processor11 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);1920 // 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);2728 // 注册该监听器用于检测监听器 bean29 beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));3031 // 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 }3738 // 注册默认的 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());34 // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime5 // (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 MessageSource10 // 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 }67 // Do not initialize FactoryBeans here: We need to leave all regular beans8 // 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 }1314 // Publish early application events now that we finally have a multicaster...15 Set<ApplicationEvent> 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 }89 // Register a default embedded value resolver if no bean post-processor10 // (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 }1516 // 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 }2122 // Stop using the temporary ClassLoader for type matching.23 beanFactory.setTempClassLoader(null);2425 // Allow for caching all bean definition metadata, not expecting further changes.26 beanFactory.freezeConfiguration();2728 // 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();34// 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();45 // Initialize lifecycle processor for this context.6 initLifecycleProcessor();78 // Propagate refresh to lifecycle processor first.9 getLifecycleProcessor().onRefresh();1011 // Publish the final event.12 publishEvent(new ContextRefreshedEvent(this));1314 // Participate in LiveBeansView MBean, if active.15 LiveBeansView.registerApplicationContext(this);16}
此时正式宣告完成 context 的refresh 工作,调用 LifecycleProcessor 的 onRefresh 方法,之后发布 ContextRefreshEvent 事件。
总结
此文对 Spring 中的几个重要的 context 进行了分析,尤其是对 AbstractApplicationContext 的主要脉络进行了梳理。
转载于:https://juejin.im/post/5cd182d36fb9a03222793435
Spring 中的 context相关推荐
- 关于Spring中的context:annotation-config/配置(开启注解)
转自:https://www.cnblogs.com/doudouxiaoye/p/5681518.html 当我们需要使用BeanPostProcessor时,直接在Spring配置文件中定义这些B ...
- spring中的context:include-filter和context:exclude-filter的区别
http://blog.csdn.net/w2393040183/article/details/50749851 <!-- 扫描@Controller注解 --><context: ...
- Spring加载context的几种方法
Spring中的context管理 Spring中IOC容器的初始化: ApplicationContext即是保存bean对象的容器,故容器本身的初始化,就是通过一系列的配置,将Applicatio ...
- spring中context:property-placeholder标签详解
spring中context:property-placeholder标签的使用说明 1,有些参数在某些阶段中是常量. 在开发阶段我们连接数据库时的url,username,password等信息 分 ...
- spring中context:property-placeholder/元素
1.有些参数在某些阶段中是常量 比如 :a.在开发阶段我们连接数据库时的连接url,username,password,driverClass等 b.分布式应用中client端访问server端所用的 ...
- Spring中配置DataSource数据源的几种选择
Spring中配置DataSource数据源的几种选择 在Spring框架中有如下3种获得DataSource对象的方法: 从JNDI获得DataSource. 从第三方的连接池获得DataSourc ...
- Spring中WebApplicationContext
ApplicationContext是Spring的核心,Context我们通常解释为上下文环境,我想用"容器"来表述它更容易理解一 些,ApplicationContext则是& ...
- Spring中使用Schedule调度
在spring中两种办法使用调度,以下使用是在spring4.0中. 一.基于application配置文件,配置入下: 1 <bean id="jobDetail" cla ...
- Spring中SmartLifecycle和Lifecycle的作用和区别
欢迎关注方志朋的博客,回复"666"获面试宝典 本文基于SpringBoot 2.5.0-M2讲解Spring中Lifecycle和SmartLifecycle的作用和区别,以及如 ...
最新文章
- PC行业为何需要华为们被搅局?
- selenium RC 环境配置
- 深度学习核心技术精讲100篇(四十四)-深度召回在招聘推荐中的挑战和实践
- java(4)——数据类型中的数值型的浮点数
- php中读取文件函数,php 读取文件夹与文件夹中文件的函数
- java中factory方法_Java的23中设计模式--工厂方法模式(Factory Method)
- 47 MM配置-采购-条件-定价过程-定义方案确认
- Nacos Spring 快速开始
- python新特性_Python3.6正式版新特性预览
- flask-sqlalchemy 数据基本操作--实例
- 金山云肖江:5G推动智慧人居产业到达新高度
- css设置table阴影浮动效果
- 【编程软件】keli烧录代码点击Download或者Debug界面卡死
- [转] Ubuntu 16.04 RTL8111/8168/8411 不能上网 经常断网解决办法
- aso关键词优化,我们该不该去做?
- 用html怎样实现抽奖效果,html5+css3实现抽奖活动的效果
- 重启防火墙(iptables)命令#service iptable restart失效
- 神经网络传递函数的选择,卷积神经网络风格迁移
- (JAVA练习)输入一个四位数,各个位的数字相加
- 【PyTorch】提高mnist模型精确度
热门文章
- 用脑电波玩游戏,这款VR体验逆天了
- 特殊的Windows消息
- Save could not be completed. Eclipse国际化的问题解决
- 使用XML创建Excel文档
- 使用Cloudera Manager部署oozie
- 跟我学雨林木风系统制作——2.涉及的技术及用到的工具介绍
- debian+pxe+preseed.cfg 安装配置
- POJ 1035, Spell checker
- C++调用matlab char16_t 重复定义
- 正则表达式:元字符,量词