SpringIoC容器的初始化 【打通refresh方法的全链路】
本章节目录:
(一)后 置 处 理 器 PostProcessor
(二)Aware 接 口 及 其 子 接 口
(三)事 件 监 听 器 模 式
(四)Refresh 方 法 源 码 详 解
(一)后 置 处 理 器 PostProcessor
PostProcessor:
本身也是一种需要注册到容器里的Bean
其里面的方法会在特定的时机被容器调用
实现不改变容器或者Bean核心逻辑的情况下对Bean进行拓展
对Bean进行包装,影响其行为、修改Bean的内容等
PostProcessor的种类:
大类分为容器级别的后置处理器以及Bean级别的后置处理器
BeanDefinitionRegistryPostProcessor
BeanFactoryPostProcessor
BeanPostProcessor
BeanDefinitionRegistryPostProcessor的使用:
下面代码意为:在BeanDefinitionRegistry注册BeanDefinition之前调用方法。执行完方法后我们就可以在容器中获取到该Bean
@Configuration
public class CustomizedBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
Class<?> clazz = User.class;//新建User的Class对象
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz);//将Class对象获取到创建BeanDefinition的工具类
GenericBeanDefinition definition = (GenericBeanDefinition)builder.getRawBeanDefinition();//通过工具类创建BeanDefinition
registry.registerBeanDefinition("user",definition);//调用注册器 注册BeanName为“user”,BeanDefinition为刚刚新建的对象。
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}
}
BeanPostProcessor的使用:
下面代码意为:在Bean注册创建之前(之后)调用方法。
@Configuration
public class CustomizedBeanPostProcessor implements BeanPostProcessor {
//Bean创建前调用
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName + "调用了postProcessBeforeInitialization()");
return bean;//返回Bean提供后续创建
}
//Bean初始化好之后调用
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName + "调用了postProcessAfterInitialization()");
return bean;
}
}
(二)Aware 接 口 及 其 子 接 口
Aware:
从Bean里获取到的容器实例并对其进行操作
该接口是个空的接口,并没有什么作用,只能当作标签使用
该接口的主要作用体现在它的子类中
Aware的关系图:(常用的子接口)
ApplicationContextAware接口主要一个方法setApplicationContext() :实现了该接口的Bean在容器创建这个Bean的实例时,将容器本身的实例作为参数传递给这个Bean使用
BeanFactory接口:获取当前的BeanFactory提供调用服务
ResourceLoaderAware:主要就是用来获取资源加载器的
BeanNameAware接口主要一个方法setBeanName(String name):实现了该接口的Bean,可以将Bean的名字传递进来供该接口使用。
(三)事 件 监 听 器 模 式
关于事件监听器设计模式的介绍:事 件 监 听 器 模 式
标准事件
Spring的ApplicationContext 提供了支持事件和代码中监听器的功能。
我们可以创建bean用来监听在ApplicationContext 中发布的事件。ApplicationEvent类和在ApplicationContext接口中处理的事件,
如果一个bean实现了ApplicationListener接口,当一个ApplicationEvent 被发布以后,bean会自动被通知。
Spring的事件驱动模型
事件驱动模型的三大组成部分:
事件:ApplicationEvent抽象类
事件监听器:ApplicationListener
事件发布器:ApplicationEventPublisher 以及 ApplicationEventMulticaster
为什么事件发布器需要ApplicationEventPublisher 接口和ApplicationEventMulticaster接口呢?
站在设计者的角度上来考虑问题呢,像Bean和容器本身就只想发布事件而不想维护事件监听器,所以Spring将事件源做了进一步分割,抽象出事件发布器接口,将ApplicationEventMulticaster作为代理。
就像ApplicationContext用我们的DefaultListableBeanFactory作为代理一样。让ApplicationEventPublisher的实现类来实现publishEvent方法里面的逻辑,那publish里面就主要去实现调用ApplicationEventMulticaster的实现类的multicastEvent方法来发布事件就好了。
AbstractApplicationContext的refresh方法里面也是这么使用两者的。
ApplicationEvent的关系图:
ApplicationEvent继承了jdk中的EventObject类,ApplicationEvent并不是单纯的表示为容器事件类。
为了给容器专门定制一个事件类还专门设置了一个子类ApplicationContextEvent(抽象类)
ApplicationContextEvent的实现子类如下:
1. 上下文更新事件(ContextRefreshedEvent):该事件会在ApplicationContext被初始化或者更新时发布。也可以在调用ConfigurableApplicationContext 接口中的refresh()方法时被触发。
2. 上下文开始事件(ContextStartedEvent) :当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件。
3. 上下文停止事件(ContextStoppedEvent) :当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件。
4. 上下文关闭事件(ContextClosedEvent) :当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁。
ApplicationListener的关系图:
ApplicationListener继承自JDK的EventListenner。JDK要求所有的监听器都继承自EventListener。
ApplicationEventMulticaster的关系图:
进入到AbstractApplicationEventMulticaster类中,可以看到里头的成员变量,看类型的名字(ListenerRetriever)就知道它是用来保存注册进来的Listener的(详细可跟进ListenerRetriever类中的成员变量applicationListeners)
AbstractApplicationEventMulticaster是抽象类,如果本地容器中没有该类的实现则默认使用实现类:SimpleApplicationEventMulticaster。
SimpleApplicationEventMulticaster类中有成员变量(Executor taskExecutor) 该成员变量为任务执行器,有执行器则意味着该类支持多线程去处理监听器的方法。
(四)Refresh 方 法 源 码 详 解
AbstractApplicationContext.Refresh()方法(大致流程):
preareRefresh | 刷新前的工作准备 |
obtainFreshBeanFactory | 获取子类刷新后的内部beanFactory实例 |
prepareBeanFactory | 为容器注册必要的系统级别的Bean |
postProcessBeanFactory | 允许容器的子类去注册postProcessor |
invokeBeanFactoryPostProcessors | 调用容器注册的容器级别的后置处理器 |
registerBeanPostProcessors | 向容器注册Bean级别的后置处理器 |
initMessageSource | 初始化国际化配置 |
initApplicationEventMulticaster | 初始化事件发布者组件 |
onRefresh | 在单例Bean初始化之前预留给子类初始化其他特殊bean的口子 |
registerListeners | 向前面的事件发布者组件注册事件监听者 |
finishBeanFactoryInitialization | 设置系统级别的服务,实例化所有非懒加载的单例 |
finishRefresh | 触发初始化完成的回调方法,并发布容器刷新完成的事件给监听者 |
resetCommonCaches | 重置Spring内核中的共用缓存 |
public void refresh() throws BeansException, IllegalStateException {
//给容器refresh加锁,避免容器处在refresh阶段时,容器进行了初始化或者销毁的操作
synchronized (this.startupShutdownMonitor) {
// 调用容器准备刷新的方法,获取容器的当前时间,同时给容器设置同步标识,具体方法
prepareRefresh();
// 告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从
//子类的refreshBeanFactory()方法启动,里面有抽象方法
//针对xml配置,最终创建内部容器,该容器负责Bean的创建于管理,此步会进行BeanDefinition的注册
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 注册一些容器中需要的系统Bean。例如classloader,beanfactoryPostProcessor等
prepareBeanFactory(beanFactory);
try {
// 允许容器的子类去注册postProcessor(钩子方法)
postProcessBeanFactory(beanFactory);
// 调用作为上下文中的bean注册的工厂处理器。
//激活在容器中注册为bean的BeanFactoryPostProcessors
//对于注解容器,org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
//方法扫描应用中所有BeanDefinition并注册到容器之中
invokeBeanFactoryPostProcessors(beanFactory);
// 注册拦截bean创建的bean处理器。
registerBeanPostProcessors(beanFactory);
// 初始化此上下文的消息源。
//找到"messageSource"的Bean提供给ApplicationContext使用
//使得ApplicationContext具有国际化能力
initMessageSource();
// 为此上下文初始化事件多播程序。
//初始化ApplicationEventMulticaster该类作为事件发布者
//可以存储所有事件监听者信息,并根据不同的事件,通知不 同的事件监听者。
initApplicationEventMulticaster();
// 在特定的上下文子类中初始化其他特殊bean。
//预留给AbstractApplicationContext的子类用于初始化其他特殊的bean,
//该方法需要在所有单例bean初始化之前调用
//比如Web容器就会去初始化一些和主题展示相关的Bean(ThemeSource)
onRefresh();
// 检查侦听器bean并注册它们(检查监听器的bean并注册他们)
//(往先前初始化的ApplicationEventMulticaster中注册监听器)
registerListeners();
//设置自定义的类型转换器ConversionService
//设置自定义AOP相关的类LoadTimeWeaverAware
// 实例化所有剩余的(非lazy-init)单例。
finishBeanFactoryInitialization(beanFactory);
// 最后一步:发布相应的事件。
//初始化容器的生命周期事件处理器,(默认使用DefaultLifecycleProcessor),调用拓展了SmartLifecycle
//当Spring容器加载所有bean并完成初始化之后,会接着回调实现该接口的类中对应的方法(start()方法,)
//并发布容器刷新完毕事件ContextRefreshedEvent给对应的事件监听者
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已经创建的单例,以避免悬浮资源。
destroyBeans();
// 重置“活跃”的旗帜。
cancelRefresh(ex);
// 将异常传播给调用者。
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
//重置Spring内核中的共用的缓存,因为我们可能再也不需要单例bean的元数据了...
resetCommonCaches();
}
}
}
1.在执行refresh的时候,首先给内部代码全部套上了synchronized锁,避免当前线程在操作容器的时候,有其他线程操作。
2.调用prepareRefresh()方法,该方法主要为刷新容器做准备
(1)设置启动时间,提供后续的日志记录和统计工作(2)将容器的状态设置为激活状态(3)设置日志等级(4)initPropertySources()【初始化Environment的propertySources属性】初始化环境默认属性值(property)
(5)getEnvironment().validateRequiredProperties()【校验是否还有些必要的属性值没有加载到】(6)查看是否有容器启动的时候就加载监听器,若是有则加载到this.earlyApplicationListeners中(7)创建事件的集合
3.⭐调用obtainFreshBeanFactory()方法,该方法对于Xml容器来讲是很重要的,方法内部调用了自类(AbstractRefreshableApplicationContext)进行BeanDefinition的注册,对于注解来讲,仅仅是调用了子类(GenericApplicationContext)的refreshBeanFactory,最终返回DefaultListableBeanFactory实例
4.调用prepareBeanFactory()方法,该方法便是为刷新容器做准备的。
(1)为内部容器(DefaultListableBeanFactory)(beanFactory)设置上外部容器的类加载器 (2)为beanFactory设置上表达式语言处理器(3)为beanFactory设置上默认的属性编辑器
(4)为beanFactory设置上ApplicationContext后置器 (5)如果某些bean依赖Aware接口的实现类,在自动装配的时候忽略的,后期处理 (6)为beanFactory修正依赖,注册一些自动装配的特殊规则
(7)往容器中设置检查内部bean的应用程序监听器 (8)判断beanFactory是否需要LTW织入器,如果是还为其设置上临时的类加载器 (9)如果系统需要则设置一些默认环境bean承载默认的系统环境变量
5. 调用invokeBeanFactoryPostProcessors()方法,该方法扫描应用中所有BeanDefinition并注册到容器之中
6.调用registerBeanPostProcessors()方法,该方法会注册拦截bean创建的bean处理器
7.调用initMessageSource()方法, 使ApplicationContext具有国际化能力
8.调用initApplicationEventMulticaster()方法,初始化事件发布器
9.调用onRefresh()方法,初始化特殊的Bean(该方法需要在所有单例bean初始化之前调用)(比如Web容器就会去初始化一些和主题展示相关的Bean(ThemeSource))(钩子方法)
10.调用registerListeners()方法,注册监听器(往先前初始化的ApplicationEventMulticaster中注册监听器)
11.调用finishBeanFactoryInitialization()方法,实例化所有剩余的(非lazy-init)单例。
(1)判断容器中是否有自动的类型转换器(有则给beanfactory设置上)(2)⭐往容器中注册默认的解析器(例如解析properties文件的PropertyPlaceholderConfigurer)
(3)获取编织器的bean实例以便进行类加载器的AOP操作(此时还没操作)(4)停止使用临时类加载器进行类型匹配
(5)允许缓存所有bean定义元数据,不希望有进一步更改(使得原先刷新好的bean稳定可靠)(6)⭐实例化所有剩余的(non-lazy-init非延时加载的)单例
12.调用finishRefresh()方法,该方法主要做一些收尾的工作。发布相应的事件
(1)清除Resource缓存 (2)为容器初始化生命周期处理器 (3)将刷新的事件传播的生命周期处理器 (4)发布最终事件(容器刷新完成事件) (5)往JMS组件中注册容器