Spring refresh()源码解析
作者:无名之辈J 发布时间:2022-09-04 18:45:52
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
// 1. 初始化前的预处理
this.prepareRefresh();
// 2. 刷新Bean工厂
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
// 3. BeanFactory的预处理配置
this.prepareBeanFactory(beanFactory);
try {
// 4. BeanFactory的后置处理
this.postProcessBeanFactory(beanFactory);
// 5. 执行BeanFactory后置处理器
this.invokeBeanFactoryPostProcessors(beanFactory);
// 6. 注册Bean的后置处理器
this.registerBeanPostProcessors(beanFactory);
// 7. 初始化MessageSource
this.initMessageSource();
// 8. 初始化事件派发器
this.initApplicationEventMulticaster();
// 9. 子类的多态onRefresh
this.onRefresh();
// 10. 注册 *
this.registerListeners();
// 11. 初始化所有剩下的单例Bean
this.finishBeanFactoryInitialization(beanFactory);
// 12. 完成容器的创建工作
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
// 13. 清除缓存
this.resetCommonCaches();
}
}
}
一、prepareRefresh:初始化前的预处理
protected void prepareRefresh() {
//设置容器启动时间
this.startupDate = System.currentTimeMillis();
//设置容器关闭状态为false
this.closed.set(false);
//设置容器激活状态为true
this.active.set(true);
if (this.logger.isDebugEnabled()) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Refreshing " + this);
} else {
this.logger.debug("Refreshing " + this.getDisplayName());
}
}
//1.1初始化属性资源
this.initPropertySources();
//1.2校验
this.getEnvironment().validateRequiredProperties();
this.earlyApplicationEvents = new LinkedHashSet();
}
1.1初始化属性值
初始化方法是个模压方法,由子类重写
protected void initPropertySources() {
}
Web容器GenericWebApplicationContext重写了此方法
protected void initPropertySources() {
//获取环境信息
ConfigurableEnvironment env = getEnvironment();
//判断是否是web配置环境
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, null);
}
}
最终由StandardServletEnvironment进行初始化
public void initPropertySources(@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {
//使用web容器工具初始化
WebApplicationContextUtils.initServletPropertySources(getPropertySources(), servletContext, servletConfig);
}
把 Servlet 的一些初始化参数放入IOC容器中
public static void initServletPropertySources(MutablePropertySources sources, @Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {
Assert.notNull(sources, "'propertySources' must not be null");
String name = "servletContextInitParams";
if (servletContext != null && sources.contains(name) && sources.get(name) instanceof StubPropertySource) {
sources.replace(name, new ServletContextPropertySource(name, servletContext));
}
name = "servletConfigInitParams";
if (servletConfig != null && sources.contains(name) && sources.get(name) instanceof StubPropertySource) {
sources.replace(name, new ServletConfigPropertySource(name, servletConfig));
}
}
1.2属性校验
通过占位符解析器校验资源集合
public void validateRequiredProperties() throws MissingRequiredPropertiesException {
this.propertyResolver.validateRequiredProperties();
}
这里的解析器作为常量在环境被实例化时就被创建出来的,PropertySourcesPropertyResolver是占位符解析器,将数据源中占位符替换成目标值
校验是否有需要被占位符修饰的属性,如果有但是资源中找不到对应属性的key就会抛出异常
public void validateRequiredProperties() {
MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();
for (String key : this.requiredProperties) {
if (this.getProperty(key) == null) {
ex.addMissingRequiredProperty(key);
}
}
if (!ex.getMissingRequiredProperties().isEmpty()) {
throw ex;
}
}
案例: 资源文件
name=zhansan
age=${name},10
encoding=utf-8
name2=${name}
测试代码
@Test
public void test1() throws Exception {
//省略propertySources
PropertyResolver propertyResolver = new PropertySourcesPropertyResolver(getPropertySources());
System.out.println(propertyResolver.getProperty("age"));
System.out.println(propertyResolver.getProperty("encoding"));
System.out.println(propertyResolver.resolvePlaceholders("must be encoding ${encoding}")); //输出must be encoding gbk
}
输出结果
10,zhansan
utf-8
must be encoding utf-8
二、obtainFreshBeanFactory:刷新Bean工厂
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//2.1刷新Bean工厂
refreshBeanFactory();
return getBeanFactory();
}
将容器刷新标识改为true,并且设置了工厂序列化id
protected final void refreshBeanFactory() throws IllegalStateException {
if (!this.refreshed.compareAndSet(false, true)) {
throw new IllegalStateException(
"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
}
this.beanFactory.setSerializationId(getId());
}
三、prepareBeanFactory:Bean工厂预处理
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 设置BeanFactory的类加载器、表达式解析器等
beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// 3.1 添加Aware执行器
beanFactory.addBeanPostProcessor(new ApplicationContextDProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// 3.2 自动注入的支持
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// 3.3 添加 * 执行器
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// Detect a LoadTimeWeaver and prepare for weaving, if found.
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// Register default environment beans.
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
3.1 ApplicationContextDProcessor:Aware执行器
ApplicationContextDProcessor实现了BeanPostProcessor的postProcessBeforeInitialization接口,在所有Bean初始化前会执行当前方法
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//判断Bean是Aware的子类
if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
return bean;
}
AccessControlContext acc = null;
if (System.getSecurityManager() != null) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareInterfaces(bean);
return null;
}, acc);
}
else {
//回调执行Aware接口
invokeAwareInterfaces(bean);
}
return bean;
}
如果当前Bean是Aware的子类,那么将Bean强转成Aware类型,通过回调将信息设置到Bean中
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
3.2 registerResolvableDependency:自动注入的支持
如果过容器中有多个相同接口的实现类,那么在自动注入的时候会注入注册的实现类
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
3.3 添加 * 执行器
ApplicationListenerDetector主要作用是添加和销毁 * ,实现了BeanPostProcessor的postProcessAfterInitialization(Bean实例化之后)方法和DestructionAwareBeanPostProcessor的postProcessBeforeDestruction(Bean销毁之前)方法
详情:https://www.jb51.net/article/277948.htm
四、BeanFactory的后置处理
这是个模压方法,由子类AnnotationConfigServletWebServerApplicationContext实现
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}
AnnotationConfigServletWebServerApplicationContext首先调了父类 ServletWebServerApplicationContext 的 postProcessBeanFactory 方法
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//4.1后置处理Bean工厂
super.postProcessBeanFactory(beanFactory);
if (this.basePackages != null && this.basePackages.length > 0) {
//basePackages为空不会执行
this.scanner.scan(this.basePackages);
}
if (!this.annotatedClasses.isEmpty()) {
this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
}
}
4.1 后置处理bean工厂
父类ServletWebServerApplicationContext首先向Bean工厂中注入了一个执行器
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//4.1.1注入执行器
beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
//4.1.2注册作用域
registerWebApplicationScopes();
}
4.1.1 WebApplicationContextServletContextAwareProcessor
WebApplicationContextServletContextAwareProcessor继承了ServletContextAwareProcessor
ServletContextAwareProcessor继承了BeanPostProcessor实现了postProcessBeforeInitialization(Bean初始化前执行)
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//注入ServletContext
if (getServletContext() != null && bean instanceof ServletContextAware) {
((ServletContextAware) bean).setServletContext(getServletContext());
}
//注入ServletConfig
if (getServletConfig() != null && bean instanceof ServletConfigAware) {
((ServletConfigAware) bean).setServletConfig(getServletConfig());
}
return bean;
}
4.1.2 registerWebApplicationScopes 注册web的应用域
// 所在类及方法:ServletWebServerApplicationContext#registerWebApplicationScopes
private void registerWebApplicationScopes() {
ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(getBeanFactory());
WebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory());
existingScopes.restore();
}
ExistingWebApplicationScopes是ServletWebServerApplicationContext类中的一个静态类
源码如下:
public static class ExistingWebApplicationScopes {
static {
Set<String> scopes = new LinkedHashSet<>();
scopes.add(WebApplicationContext.SCOPE_REQUEST);
scopes.add(WebApplicationContext.SCOPE_SESSION);
SCOPES = Collections.unmodifiableSet(scopes);
}
// 这是构造方法,大概就是根据SCOPES获取beanFactory中已经注册的scope,然后放入scopes
// 需要注意的是,在上面的方法中,第二行才在向beanFactory中注册,也就是这时的beanFactory里面没有request和session这两个scop
// 所以这里就完成了beanFactory的赋值。建议打断点进去看看
public ExistingWebApplicationScopes(ConfigurableListableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
for (String scopeName : SCOPES) {
Scope scope = beanFactory.getRegisteredScope(scopeName);
if (scope != null) {
this.scopes.put(scopeName, scope);
}
}
}
// 由于上面的方法并没有值存入scopes,所以这里也就没执行里面的内容
public void restore() {
this.scopes.forEach((key, value) -> {
if (logger.isInfoEnabled()) {
logger.info("Restoring user defined scope " + key);
}
this.beanFactory.registerScope(key, value);
});
}
}
WebApplicationContextUtils.registerWebApplicationScopes(),这个方法就是向beanFactory注册web的scope了,源码如下
public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory) {
registerWebApplicationScopes(beanFactory, null);
}
public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory,
@Nullable ServletContext sc) {
// 注册作用域
beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());// 注册request SCOP
beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope());// 注册session SCOP
if (sc != null) {
ServletContextScope appScope = new ServletContextScope(sc);
beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope); // 注册application SCOP
// Register as ServletContext attribute, for ContextCleanupListener to detect it.
sc.setAttribute(ServletContextScope.class.getName(), appScope);
}
// 添加依赖项
beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory());
beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());
if (jsfPresent) {
FacesDependencyRegistrar.registerFacesDependencies(beanFactory);
}
}
来源:https://juejin.cn/post/7202531472720789559


猜你喜欢
- 一、什么是网关限流:在微服务架构中,网关层可以屏蔽外部服务直接对内部服务进行调用,对内部服务起到隔离保护的作用,网关限流,顾名思义,就是通过
- 多个条件使用Map传递参数进行批量删除1、使用场景因为项目需要针对资源文件(视频、音频、文档),编辑时候可能出现以下3种情况:实现的项目效果
- 直接上代码public static class ImageCompress { /// <su
- 基本数据类型变量就是用来储存值而保留的内存位置。这就意味着当你创建一个变量时就会在内存中占用一定的空间。基于变量的数据类型,操作系统会进行内
- 最近在项目中用到了上下滚动展示条目内容,就使用kotlin简单编写实现了一下该功能。使用kotlin实现viewflipper展示textv
- 一、maven * 搭建使用Nexus进行搭建,网上教程很多,不多赘述了。二、gradle配置在build.gradle文件的根节点中添加以下
- 前言在机器学习中,卷积神经网络是一种深度前馈人工神经网络,已成功地应用于图像识别。目前,很多的车牌识号识别,人脸识别等都采用卷积神经网络,可
- 这篇文档主要关注下配置修改后对应的 Java 对象是如何更新,并不关注整体的配置改动流程所有代码都来自 apollo-client 项目更新
- 1.Java Io流的概念,分类,类图。1.1 Java Io流的概念java的io是实现输入和输出的基础,可以方便的实现数据的输入和输出操
- 1、购买或本地生成ssl证书要使用https,首先需要证书,获取证书的两种方式:1、自己通过keytool生成2、通过证书授权机构购买###
- Android Studio下载(下文统称AS)AS最新版下载请戳:AS下载Android SDK下载SDK安装器下载SDK安装器下载请戳:
- Kotlin开发Android应用实例详解我们简单的知道了Kotlin这门新语言的优势,也接触了一些常见的语法及其简单的使用,相信你会对它有
- 什么是代理模式代理模式是开发中常见的一种设计模式,使用代理模式可以很好的对程序进行横向扩展。代理,顾名思义就是一个真实对象会存在一个代理对象
- spring batch简介spring batch是spring提供的一个数据处理框架。企业域中的许多应用程序需要批量处理才能在关键任务环
- maven项目中在pom.xml中依赖2个jar包,其他的spring的jar包省略:<dependency> &
- https://www.jb51.net/article/114838.htm这篇文章很详细的介绍了JS的跨域,给出的解决方案是spring
- C# ping网络IP 实现网络状态检测的方法public string GetHostNameByIp(string&
- 背景项目中经常会用到消息推送功能,关于推送技术的实现,我们通常会联想到轮询、comet长连接技术,虽然这些技术能够实现,但是需要反复连接,对
- 1. 二叉树的顺序存储1.1 存储方式使用数组保存二叉树结构,方式即将二叉树用 层序遍历 方式放入数组中。一般只适合表示完全二叉树,这种方式
- 最近的项目中,想做到一种能够吸引眼球的一种角色选择浏览效果Demo源码:点击打开链接最终实现了下按如下图这么一种浏览效果:效果图一效果图二可