浅析IOC容器启动过之AbstractApplicationContext#refresh()方法
ApplicationContext#refresh()方法是Spring容器启动的核心中的核心,逻辑也是异常的复杂【基于5.0.6.RELEASE】。
Spring Bean声明周期流程图
Spring Bean的完整生命周期从创建Spring容器开始,直到最终Spring容器销毁Bean,这其中包含了一系列关键点。
简单分类如下:
- 工厂后置处理器(BeanFactoryPostProcessor):这个包括了AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer等等非常有用的工厂后处理器 接口的方法。工厂后处理器也是容器级的。
- 容器级别生命周期处理器:包括了InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为“后处理器”。
- Bean级生命周期接口方法(仅作用于某个Bean):这个包括了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这些接口的方法
- Bean自身的方法:这个包括了Bean本身调用的方法和通过配置文件中<bean>的init-method和destroy-method指定的方法
一般如果我们的项目是全注解驱动的,那么我们的容器实例就为AnnotationConfigWebApplicationContext。若是xml配置驱动,则为XmlWebApplicationContext。
为了更方便了解容器类的继承关系,贴出如下类继承图:
refresh()方法所有的ApplicationContext子类都没重写,只有AbstractApplicationContext里有实现过(接口定义在ConfigurableApplicationContext),因此我们看起来也容易了。
refresh()源码 宏观步骤说明
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//容器刷新前的准备,设置上下文状态,获取属性,验证必要的属性等
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 获取新的beanFactory,销毁原有beanFactory、为每个bean生成BeanDefinition等 注意,此处是获取新的,销毁旧的,这就是刷新的意义
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//配置标准的beanFactory,设置ClassLoader,设置SpEL表达式解析器等
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
//模板方法,允许在子类中对beanFactory进行后置处理。
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
//实例化并调用所有注册的beanFactory后置处理器(实现接口BeanFactoryPostProcessor的bean)。
//在beanFactory标准初始化之后执行 例如:PropertyPlaceholderConfigurer(处理占位符)
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
//实例化和注册beanFactory中扩展了BeanPostProcessor的bean。
//例如:
//AutowiredAnnotationBeanPostProcessor(处理被@Autowired注解修饰的bean并注入)
//RequiredAnnotationBeanPostProcessor(处理被@Required注解修饰的方法)
//CommonAnnotationBeanPostProcessor(处理@PreDestroy、@PostConstruct、@Resource等多个注解的作用)等。
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
//初始化国际化工具类MessageSource
initMessageSource();
// Initialize event multicaster for this context.
//初始化事件广播器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//模板方法,在容器刷新的时候可以自定义逻辑(子类自己去实现逻辑),不同的Spring容器做不同的事情
onRefresh();
// Check for listener beans and register them.
//注册监听器,并且广播early application events,也就是早期的事件
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//非常重要。。。实例化所有剩余的(非懒加载)单例Bean。(也就是我们自己定义的那些Bean们)
//比如invokeBeanFactoryPostProcessors方法中根据各种注解解析出来的类,在这个时候都会被初始化 扫描的 @Bean之类的
//实例化的过程各种BeanPostProcessor开始起作用~~~~~~~~~~~~~~
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
//refresh做完之后需要做的其他事情
//清除上下文资源缓存(如扫描中的ASM元数据)
//初始化上下文的生命周期处理器,并刷新(找出Spring容器中实现了Lifecycle接口的bean并执行start()方法)。
//发布ContextRefreshedEvent事件告知对应的ApplicationListener进行响应的操作
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
//如果刷新失败那么就会将已经创建好的单例Bean销毁掉
destroyBeans();
// Reset 'active' flag.
//重置context的活动状态 告知是失败的
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...
// 失败与否,都会重置Spring内核的缓存。因为可能不再需要metadata给单例Bean了。
resetCommonCaches();
}
}
}
通过上面的注释,已经能够比较宏观的了解到容器的一个初始化过程了,那么接下来,将针对每一个步骤,进行微观源码级别的解释说明。
refresh() 具体源码解析
refresh() 第一步:prepareRefresh()
protected void prepareRefresh() {
//记录容器启动时间,然后设立对应的标志位
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
// 打印info日志:开始刷新this此容器了
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}
// Initialize any placeholder property sources in the context environment
// 这是扩展方法,由子类去实现,可以在验证之前为系统属性设置一些值可以在子类中实现此方法
// 因为我们这边是AnnotationConfigApplicationContext,可以看到不管父类还是自己,都什么都没做,所以此处先忽略
initPropertySources();
// Validate that all properties marked as required are resolvable
// see ConfigurablePropertyResolver#setRequiredProperties
//这里有两步,getEnvironment(),然后是是验证是否系统环境中有RequiredProperties参数值 如下详情
// 然后管理Environment#validateRequiredProperties 后面在讲到环境的时候再专门讲解吧
// 这里其实就干了一件事,验证是否存在需要的属性
getEnvironment().validateRequiredProperties();
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
// 初始化容器,用于装载早期的一些事件
this.earlyApplicationEvents = new LinkedHashSet<>();
}
AbstractApplicationContext#getEnvironment()
getEnvironment()的顶层接口位于:EnvironmentCapable,有如下实现(注意ConfigurableApplicationContext是接口,所以其实上容器的实现只有AbstractApplicationContext):
Demo代码如下:
@Autowired
private BeanFactory beanFactory;
@Autowired
private ApplicationContext applicationContext;
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
//web环境下
@Autowired
private HttpServletRequest request;
@Autowired
private HttpServletResponse response;
@Autowired
private HttpSession session;
@Autowired
private WebRequest webRequest;
@Override
public Object hello() {
System.out.println(beanFactory); //org.springframework.beans.factory.support.DefaultListableBeanFactory@3ff27f35
System.out.println(applicationContext); //Root WebApplicationContext: startup date [T ...
System.out.println(applicationEventPublisher); //Root WebApplicationContext: startup date [T ...
// 我们发现的是同一个Bean
System.out.println(System.identityHashCode(applicationEventPublisher) == System.identityHashCode(applicationContext)); //true
//web环境
// =================必须说明一点:这里注入的所有web对象,都是线程安全的=================
// 请求N次,每次输出的HashCode都是一样的,那怎么还没有线程安全问题呢?具体看下面分解原因
System.out.println(System.identityHashCode(request));
System.out.println(request.getClass()); //class com.sun.proxy.$Proxy22 这是个代理对象哟~~~~
System.out.println(request); //Current HttpServletRequest
System.out.println(response); //Current HttpServletResponse
System.out.println(session); //Current HttpSession
System.out.println(webRequest); //Current ServletWebRequest
return "service hello";
}
下面的web容器AbstractRefreshableWebApplicationContext就会设置一些初始值:
@Override
protected void initPropertySources() {
ConfigurableEnvironment env = getEnvironment();
// 初始化web环境中的初始值(比如init等,这个后续会说)
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, null);
}
}
@Override
public ConfigurableEnvironment getEnvironment() {
if (this.environment == null) {
this.environment = createEnvironment();
}
return this.environment;
}
// 这个方法需要注意一下,默认是StandardEnvironment,但是它是protected方法设计,所以之类可以重写(如下图)
protected ConfigurableEnvironment createEnvironment() {
return new StandardEnvironment();
}
//StandardServletEnvironment.initPropertySources(this.servletContext, null)
@Override
public void initPropertySources(@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {
// 将 servletContext、servletConfig 添加到 propertySources里(ServletConfigPropertySource)
//ServletConfigPropertySource作用:reads init parameters from ServletConfig
WebApplicationContextUtils.initServletPropertySources(getPropertySources(), servletContext, servletConfig);
}
它们都是web环境下的上下文,因此重写的方式也是一模一样:
//StandardServletEnvironment是web环境上下文里的Enviroment
@Override
protected ConfigurableEnvironment createEnvironment() {
return new StandardServletEnvironment();
}
refresh() 第二步:ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory()
实际上就是重新创建一个bean工厂,并销毁原工厂。主要工作是创建DefaultListableBeanFactory实例,解析配置文件,注册Bean的定义信息。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
在spring中,基本上各司其职,每个类都有每个类的作用。其中refreshBeanFactory()是具体的刷新BeanFactory,负责这个工作在类AbstractRefreshableApplicationContext#refreshBeanFactory中,顾名思义这是专门用来刷新的:
@Override
protected final void refreshBeanFactory() throws BeansException {
// 判断是否已经存在BeanFactory,存在则销毁所有Beans,并且关闭BeanFactory
// 避免重复加载BeanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 创建具体的beanFactory,这里创建的是DefaultListableBeanFactory,最重要的beanFactory spring注册及加载bean就靠它
// createBeanFactory()这个方法,看下面,还有得说的
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
// 这句比较简单,就是把当前旧容器的一些配置值复制给新容器
// allowBeanDefinitionOverriding属性是指是否允对一个名字相同但definition不同进行重新注册,默认是true。
// allowCircularReferences属性是指是否允许Bean之间循环引用,默认是true.
// 这两个属性值初始值为空:复写此方法即可customizeBeanFactory
customizeBeanFactory(beanFactory);
// 这个就是最重要的了,加载所有的Bean配置信息,具体如下详细解释
// 它属于模版方法,由子类去实现加载的方式
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
createBeanFactory()
// 创建的时候就是new了一个工厂:DefaultListableBeanFactory 这个时候工厂里面所有东西都是默认值,很多还没有完成初始化属性的设置呢
protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
// 给设置父的BeanFactory,若存在的话
public AbstractAutowireCapableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
this();
setParentBeanFactory(parentBeanFactory);
}
// 父类空构造器有这么些语句
public AbstractAutowireCapableBeanFactory() {
super();
// 这里是重点。忽略自动装配。这里指定的都是接口。什么意思呢?
// ignoreDependencyInterface的真正意思是在自动装配时忽略指定接口的实现类中,对外的依赖。(这里面注意:@Autowired和它的关系,其实是有坑的,后续会专门讲解这个坑)
ignoreDependencyInterface(BeanNameAware.class);
ignoreDependencyInterface(BeanFactoryAware.class);
ignoreDependencyInterface(BeanClassLoaderAware.class);
}
//找到父的,若存在就返回 若存在父容器就存在父的BeanFactory
@Nullable
protected BeanFactory getInternalParentBeanFactory() {
return (getParent() instanceof ConfigurableApplicationContext) ?
((ConfigurableApplicationContext) getParent()).getBeanFactory() : getParent();
}
AnnotationConfigWebApplicationContext#loadBeanDefinitions()方法,加载Bean的定义 (XmlWebApplicationContext的实现不一样,因为它是加载xml配置文件)
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
// 初始化这个脚手架 其实就是直接new出实例。具体做的工作,下面有相关博文链接
AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);
ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);
// 生成Bean的名称的生成器,如果自己没有setBeanNameGenerator(可以自定义),这里目前为null
BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
if (beanNameGenerator != null) {
reader.setBeanNameGenerator(beanNameGenerator);
scanner.setBeanNameGenerator(beanNameGenerator);
//若我们注册了beanName生成器,那么就会注册进容器里面
beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
}
//这是给reader和scanner注册scope的解析器 此处为null
ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
if (scopeMetadataResolver != null) {
reader.setScopeMetadataResolver(scopeMetadataResolver);
scanner.setScopeMetadataResolver(scopeMetadataResolver);
}
// 此处注意了:annotatedClasses和basePackages一般是选其一(当然看到此处,他们是可以并存的)
//我们可以自己指定annotatedClasses 配置文件,同时也可以交给下面扫描
if (!this.annotatedClasses.isEmpty()) {
// 这里会把所有的配置文件输出=======info日志 请注意观察控制台
if (logger.isInfoEnabled()) {
logger.info("Registering annotated classes: [" +
StringUtils.collectionToCommaDelimitedString(this.annotatedClasses) + "]");
}
// 若是指明的Bean,就交给reader去处理,至于怎么处理,见上篇博文的doRegisterBean去怎么解析每一个Config Bean的
reader.register(ClassUtils.toClassArray(this.annotatedClasses));
}
// 也可以是包扫描的方式,扫描配置文件的Bean
if (!this.basePackages.isEmpty()) {
// 输出对应的info日志
if (logger.isInfoEnabled()) {
logger.info("Scanning base packages: [" +
StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]");
}
// 这里重要了,scan方法具体做了什么事,上篇博文也有详细的介绍,请参阅
scanner.scan(StringUtils.toStringArray(this.basePackages));
}
// 此处的意思是,也可以以全类名的形式注册。比如可以调用setConfigLocations设置(这在xml配置中使用较多) 可以是全类名,也可以是包路径
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (String configLocation : configLocations) {
try {
Class<?> clazz = ClassUtils.forName(configLocation, getClassLoader());
reader.register(clazz);
} catch (ClassNotFoundException ex) {
// 发现不是全类名,那就当作包扫描吧
int count = scanner.scan(configLocation);
}
}
}
}
现在BeanFactory已经创建了,并且Config配置文件的Bean定义已经注册完成了(备注:其它单例Bean是还没有解析的~~~~)
显然,下面的步骤大都把BeanFactory传进去了,都是基于此Bean工厂的了~~~
refresh() 第三步:prepareBeanFactory(beanFactory)
这个方法是配置工厂的标准上下文特征
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 设置beanFactory的classLoader为当前context的classLoader
beanFactory.setBeanClassLoader(getClassLoader());
// 设置EL表达式解析器(Bean初始化完成后填充属性时会用到)
// spring3增加了表达式语言的支持,默认可以使用#{bean.xxx}的形式来调用相关属性值
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
// 设置属性注册解析器PropertyEditor 这个主要是对bean的属性等设置管理的一个工具
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// 将当前的ApplicationContext对象交给ApplicationContextAwareProcessor类来处理,从而在Aware接口实现类中的注入applicationContext等等
// 添加了一个处理aware相关接口的beanPostProcessor扩展,主要是使用beanPostProcessor的postProcessBeforeInitialization()前置处理方法实现aware相关接口的功能
// 类似的还有ResourceLoaderAware、ServletContextAware等等等等
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 下面是忽略的自动装配(也就是实现了这些接口的Bean,不要Autowired自动装配了)
// 默认只有BeanFactoryAware被忽略,所以其它的需要自行设置
// 因为ApplicationContextAwareProcessor把这5个接口的实现工作做了(具体你可参见源码) 所以这里就直接忽略掉
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// 设置几个"自动装配"规则======如下:
// 如果是BeanFactory的类,就注册beanFactory
// 如果是ResourceLoader、ApplicationEventPublisher、ApplicationContext等等就注入当前对象this(applicationContext对象)
// 此处registerResolvableDependency()方法注意:它会把他们加入到DefaultListableBeanFactory的resolvableDependencies字段里面缓存这,供后面处理依赖注入的时候使用 DefaultListableBeanFactory#resolveDependency处理依赖关系
// 这也是为什么我们可以通过依赖注入的方式,直接注入这几个对象比如ApplicationContext可以直接依赖注入
// 但是需要注意的是:这些Bean,Spring的IOC容器里其实是没有的。beanFactory.getBeanDefinitionNames()和beanFactory.getSingletonNames()都是找不到他们的,所以特别需要理解这一点
// 至于容器中没有,但是我们还是可以@Autowired直接注入的有哪些,请看下图:
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// 注册这个Bean的后置处理器:在Bean初始化后检查是否实现了ApplicationListener接口
// 是则加入当前的applicationContext的applicationListeners列表 这样后面广播事件也就方便了
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// 检查容器中是否包含名称为loadTimeWeaver的bean,实际上是增加Aspectj的支持
// AspectJ采用编译期织入、类加载期织入两种方式进行切面的织入
// 类加载期织入简称为LTW(Load Time Weaving),通过特殊的类加载器来代理JVM默认的类加载器实现
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
// 添加BEAN后置处理器:LoadTimeWeaverAwareProcessor
// 在BEAN初始化之前检查BEAN是否实现了LoadTimeWeaverAware接口,
// 如果是,则进行加载时织入,即静态代理。
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// 注入一些其它信息的bean,比如environment、systemProperties、SystemEnvironment等
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());
}
}
说个小细节:@Autowired和@Qualifier一起使用时,@Qualifier的值需保证容器里一定有,否则启动报错。
特别地:IOC容器中没有Bean,但是我们还是可以依赖注入的Bean如下(resolvableDependencies):
refresh() 第四步:postProcessBeanFactory(beanFactory)
模版方法。因为beanFactory都准备好了,子类可以自己去实现自己的逻辑。
比如一些web的ApplicationContext,就实现了自己的逻辑,做一些自己的web相关的事情。此处我们就是web环境下,因此会进来。
AbstractRefreshableWebApplicationContext#postProcessBeanFactory方法:
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//注册ServletContextAwareProcessor 这样任意Bean都可以很方便的获取到ServletContext了 同时忽略另外两个,因为ServletContextAwareProcessor 都把事情都做了
beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
//注册web环境,包括request、session、golableSession、application
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
//注册servletContext、contextParamters、contextAttributes 、servletConfig单例bean
WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
}
refresh() 第五步:invokeBeanFactoryPostProcessors(beanFactory)
invokeBeanFactoryPostProcessors执行BeanFactory后置处理器,当然前提是你已经在容器中注册过此处理器了。
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
// 这里就是定制:如果loadTimeWeaver这个Bean存在,那么就会配置上运行时织入的处理器LoadTimeWeaverAwareProcessor
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
这里面我们必须先看看getBeanFactoryPostProcessors()这个方法:
public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
return this.beanFactoryPostProcessors;
}
这里非常有意思。方法非常简单,但有意思在于:它不是返回Spring容器里面的Processors,而是你自己注册的(你自己手动set的),也就是说我们自己手动调用set方法添加进去,就能够执行。并不需要自己配置@Bean或者在xml里配置。
那么重点就在于PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors,它的代码可谓非常非常多:
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
// 这个doc说明很清楚:不管怎么样,先执行BeanDefinitionRegistryPostProcessors
// 需要注意的是BeanDefinitionRegistryPostProcessors 为 BeanFactoryPostProcessor 的子接口 它新增了方法:void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
// BeanFactoryPostProcessor 的方法为;void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
// 所以BeanDefinitionRegistryPostProcessors,它可以我们介入,改变Bean的一些定义信息
Set<String> processedBeans = new HashSet<>();
// 只有此beanFactory 是BeanDefinitionRegistry 才能执行BeanDefinitionRegistryPostProcessor,才能修改Bean的定义嘛~
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
// 此处安放了两个容器,一个装载普通的BeanFactoryPostProcessor
// 另外一个装载和Bean定义有关的 BeanDefinitionRegistryPostProcessor
// 另外都是LinkedList,所以执行顺序和set进去的顺序是保持一样的
List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new LinkedList<>();
// 这里是我们自己的set进去的,若没set,这里就是空(若是Sprng容器里的,下面会处理,见下面)
// 从此处可以看出,我们手动set进去的,最最最最有限执行的
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
// 这里执行post方法,然后然后吧它缓冲起来了,放在了registryProcessors里
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
// 缓冲起来常规的处理器
regularPostProcessors.add(postProcessor);
}
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// Separate between BeanDefinitionRegistryPostProcessors that implement
// PriorityOrdered, Ordered, and the rest.
// 接下来,就是去执行Spring容器里面的一些PostProcessor了。他们顺序doc里也写得很清楚:
// 先执行实现了PriorityOrdered接口的,然后是Ordered接口的,最后执行剩下的
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
// 先从容器中拿出来所有的BeanDefinitionRegistryPostProcessor 然后先执行PriorityOrdered
// 本例中有一个这个类型的处理器:ConfigurationClassPostProcessor(显然是处理@Configuration这种Bean的)
// 至于这个Bean是什么时候注册进去的,前面有。在loadBeanDefinitions()初始化AnnotatedBeanDefinitionReader的时候调用的AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)方法的时候,注册了6个Bean
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
// processedBeans也顺带保存了一份,保存的是bean的Name哦~
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
// 排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
// 此处缓冲起来(需要注意的是,是排序后,再放进去的 这样是最好的)
registryProcessors.addAll(currentRegistryProcessors);
// 这个方法很简单,就是吧currentRegistryProcessors里面所有的处理器for循环一个个的执行掉(本处只有ConfigurationClassPostProcessor,详见我的另一篇专门博文讲解)
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
// 此处把当前持有的执行对象给清空了,需要注意。以方便装载后续执行的处理器们
currentRegistryProcessors.clear();
// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
// 此处逻辑完全同上 处理实现Order接口的RegistryProcessors
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
// 最后执行,两个排序接口都没有实现的BeanDefinitionRegistryPostProcessor们,并且也缓存起来
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
// 现在,这里很明显:去执行BeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法
// 以及 顶层接口BeanFactoryPostProcessor的postProcessBeanFactory方法
// 我们当前环境regularPostProcessors长度为0.registryProcessors有一个解析@Configuration的处理器
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
} else {
// Invoke factory processors registered with the context instance.
// 若是普通的Bean工厂,就直接执行set进来的后置处理器即可(因为容器里就没有其它Bean定义了)
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// 下面就是开始执行BeanFactoryPostProcessor 基本也是按照上面的顺序来执行的
// 上面9个Bean,我们知道 也就ConfigurationClassPostProcessor是实现了此接口的。因此本环境下,只有它了,并且它在上面还已经执行了
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
// 这里面注意,已经执行过的后置处理器,就不要再执行了
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// Finally, invoke all other BeanFactoryPostProcessors.
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values...
beanFactory.clearMetadataCache();
}
postProcessBeanDefinitionRegistry和postProcessBeanFactory方法:
两者都存在于BeanDefinitionRegistryPostProcessor接口中,表明其既可以自定义BeanDefinition并注册进容器中也可以对beanFactory修改。
那为什么逻辑要先执行postProcessBeanDefinitionRegistry然后再执行postProcessBeanFactory呢?
因为postProcessBeanDefinitionRegistry是用来创建bean定义的,而postProcessBeanFactory是修改BeanFactory,当然postProcessBeanFactory也可以修改bean定义的。为了保证在修改之前所有的bean定义的都存在,所以优先执行postProcessBeanDefinitionRegistry。如不是以上顺序,可能会出现修改某个bean定义的报错,因为此bean定义的还没有被创建。
至此,invokeBeanFactoryPostProcessors(beanFactory)这一步就完成了。这一步主要做了:
(1)执行了BeanDefinitionRegistryPostProcessor(此处只有ConfigurationClassPostProcessor)
(2)执行了BeanFactoryPostProcessor
(3)完成了@Configuration配置文件的解析,并且把扫描到的、配置的Bean定义信息都加载进容器里
(4)完成了对@Configuration配置文件的加强,使得管理Bean依赖关系更加的方便了
这里注册Bean定义的时候有个小细节:我们都知道Spring支持FactoryBean的模式,所以这里如果发现注册的Bean为FactoryBean类型的话,会把自己以及getObject()出来的对象的Bean定义都注册上去。并且FactoryBean的名称为:beanName = FACTORY_BEAN_PREFIX + beanName; 这一点需要注意。
上面5个步骤,Bean工厂完全准备好了,并且也注册好了所有的Bean的定义信息(此时Bean还并没有创建)。也完成了对配置文件的解析,可以说Spring IOC容器的大的准备工作已经完成了,接下来就是对Bean的一些初始化、以及操作~
refresh() 第六步:registerBeanPostProcessors(beanFactory)
在讲解这个方法之前先看下什么是BeanPostProcessor,下面是BeanPostProcessor的代码:
public interface BeanPostProcessor {
// 在Bean实例化/依赖注入完毕以及自定义的初始化方法之前调用。什么叫自定义初始化方法:比如init-method、比如@PostConstruct标、比如实现InitailztingBean接口的方法等等
// bean:这个Bean实例 beanName:bean名称
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
// 在上面基础上,初始化方法之后调用
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
接口中两个方法不能返回null,如果返回null,那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象 ,因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中。
BeanFactory和ApplicationContext注册Bean的后置处理器不同点:
ApplicationContext直接使用@Bean注解,就能向容器注册一个后置处理器。
原因:它注册Bean的时候,会先检测是否实现了BeanPostProcessor接口,并自动把它们注册为后置处理器。所在在它这部署一个后置处理器和注册一个普通的Bean,是没有区别的。
BeanFactory必须显示的调用:void addBeanPostProcessor(BeanPostProcessor beanPostProcessor)才能注册进去。
Spring 可以注册多个Bean的后置处理器,是按照注册的顺序进行调用的。若想定制顺序,可以实现@Order或者实现Order接口~
源码解读
先说说:((DefaultListableBeanFactory) beanFactory).getBeanPostProcessors();这个方法:
public List<BeanPostProcessor> getBeanPostProcessors() {
return this.beanPostProcessors;
}
它返回的是所有的通过BeanFactory#addBeanPostProcessor方法添加进去的后置处理器,会存在这个List里面。
还有就是这个内部类:(一共4个,是容器启动时,用BeanFactory添加进去的Bean后置处理器)
而这个方法getBeanNamesForType是从Bean定义信息里面去找:主要是如下几个属性缓存上的:
(所以请注意和getBeanPostProcessors的结果区分开来,虽然都是BeanPostProcessor)
/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
/** Map of singleton and non-singleton bean names, keyed by dependency type */
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);
/** Map of singleton-only bean names, keyed by dependency type */
private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64);
/** List of bean definition names, in registration order */
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
这些其实就是IOC容器的本质:一堆Map。
具体源码:
// 发现它又是委托给PostProcessorRegistrationDelegate 去做的
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
// 从所与Bean定义中提取出BeanPostProcessor类型的Bean,显然,最初的6个bean,有三个是BeanPostProcessor:
// AutowiredAnnotationBeanPostProcessor RequiredAnnotationBeanPostProcessor CommonAnnotationBeanPostProcessor
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// Register BeanPostProcessorChecker that logs an info message when
// a bean is created during BeanPostProcessor instantiation, i.e. when
// a bean is not eligible for getting processed by all BeanPostProcessors.
// 此处有点意思了,向beanFactory又add了一个BeanPostProcessorChecker,并且此事后总数设置为了getBeanPostProcessorCount和addBeanPostProcessor的总和(+1表示自己)
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
// 此处注意:第一个参数beanPostProcessorTargetCount表示的是处理器的总数,总数(包含两个位置离的,用于后面的校验)
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// Separate between BeanPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
// 同样的 先按优先级,归类了BeanPostProcessor
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
// MergedBeanDefinitionPostProcessor则是在合并处理Bean定义的时候的回调。这个东东按我的理解也基本是框架内部使用的,用户不用管
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, register the BeanPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
// Next, register the BeanPostProcessors that implement Ordered.
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
// Now, register all regular BeanPostProcessors.
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
// Finally, re-register all internal BeanPostProcessors.
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
// Re-register post-processor for detecting inner beans as ApplicationListeners,
// moving it to the end of the processor chain (for picking up proxies etc).
// 最后此处需要注意的是:Spring还给我们注册了一个Bean的后置处理器:ApplicationListenerDetector 它的作用:用来检查所有得ApplicationListener
// 有的人就想问了:之前不是注册过了吗,怎么这里又注册一次呢?其实上面的doc里面说得很清楚:
// Re-register重新注册这个后置处理器。把它移动到处理器连条的最后面,最后执行(小技巧是:先remove,然后执行add操作~~~ 自己可以点进addBeanPostProcessor源码可以看到这个小技巧)
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
// 把类型是BeanPostProcessor的Bean,注册到beanFactory里面去
private static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {
for (BeanPostProcessor postProcessor : postProcessors) {
beanFactory.addBeanPostProcessor(postProcessor);
}
}
这一步:我们从所有的@Bean定义中抽取出来了BeanPostProcessor然后都注册进去,等待后面的的顺序调用。
refresh() 第七步:initMessageSource()
初始化消息源。
protected void initMessageSource() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 判断是否已经存在名为“messageSource”的Bean了(一般情况下,我们都是没有的)
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
// 从容器里拿出这个messageSource
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
// Make MessageSource aware of parent MessageSource.
// 设置父属性。。。。。。。。。。。。。
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
if (hms.getParentMessageSource() == null) {
// Only set parent context as parent MessageSource if no parent MessageSource
// registered already.
hms.setParentMessageSource(getInternalParentMessageSource());
}
}
}
else {
// Use empty MessageSource to be able to accept getMessage calls.
DelegatingMessageSource dms = new DelegatingMessageSource();
// 其实就是获取到父容器的messageSource字段(否则就是getParent()上下文自己)
dms.setParentMessageSource(getInternalParentMessageSource());
// 给当前的messageSource赋值
this.messageSource = dms;
// 把messageSource作为一个单例的Bean注册进beanFactory工厂里面
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
}
}
这部分逻辑比较简单:向容器里注册一个一个事件源的单例Bean:MessageSource
refresh() 第八步:initApplicationEventMulticaster()
初始化Spring的事件多播器:ApplicationEventMulticaster
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster = beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
} else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
}
}
这个逻辑太简单了,一句话:若用户自己定义了这个Bean(备注:Bean名称必须是"applicationEventMulticaster"哦),就以用户的为准。否则注册一个系统默认的SimpleApplicationEventMulticaster
refresh() 第九步:onRefresh()
类似于第四步的postProcessBeanFactory,它也是个模版方法。本环境中的实现为:AbstractRefreshableWebApplicationContext#onRefresh方法:
@Override
protected void onRefresh() {
this.themeSource = UiApplicationContextUtils.initThemeSource(this);
}
web环境,所以去初始化了它的主题。
refresh() 第十步:registerListeners();
我们知道,上面我们已经把事件源、多播器都注册好了,这里就是注册监听器了:
protected void registerListeners() {
// 这一步和手动注册BeanDefinitionRegistryPostProcessor一样,可以自己通过set手动注册监听器 然后是最新执行的(显然此处我们无自己set)
for (ApplicationListener<?> listener : getApplicationListeners()) {
// 把手动注册的监听器绑定到广播器
getApplicationEventMulticaster().addApplicationListener(listener);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
// 取到容器里面的所有的监听器的名称,绑定到广播器 后面会广播出去这些事件的
// 同时提醒大伙注意:此处并没有说到ApplicationListenerDetector这个东东,下文会分解
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// Publish early application events now that we finally have a multicaster...
// 这一步需要注意了:如果存在早期应用事件,这里就直接发布了(同时就把earlyApplicationEvents该字段置为null)
//
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
refresh() 第十一步:finishBeanFactoryInitialization(beanFactory)
进行这一步之前,我这里截图看看,当前工厂里的Bean的的一个情况:
容器内所有的单例Bean们: 有的是提前经历过getBean()被提前实例化了,有的是直接addSingleton()方法直接添加的。
容器内所有的Bean定义信息: 我们能够发现,我们自己@Bean进去的目前都仅仅存在于Bean定义信息内,还并没有真正的实例化。这就是我们这一步需要做的事~~~~
创建所有非懒加载的单例类(并invoke BeanPostProcessors)。这一步可谓和我们开发者打交道最多的,我们自定义的Bean绝大都是在这一步被初始化的,包括依赖注入等等~
因此了解这一步,能让我们更深入的了解Spring是怎么管理我们的Bean的声明周期,以及依赖关系的。
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
// 初始化上下文的转换服务,ConversionService是一个类型转换接口
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService( beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// Register a default embedded value resolver if no bean post-processor
// (such as a PropertyPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
// 设置一个内置的值处理器(若没有的话),该处理器作用有点像一个PropertyPlaceholderConfigurer bean
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
// 注意此处已经调用了getBean方法,初始化LoadTimeWeaverAware Bean
// getBean()方法的详细,下面会详细分解
// LoadTimeWeaverAware是类加载时织入的意思
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// Stop using the temporary ClassLoader for type matching.
// 停止使用临时的类加载器
beanFactory.setTempClassLoader(null);
// Allow for caching all bean definition metadata, not expecting further changes.
// 缓存(冻结)所有的bean definition数据,不期望以后会改变
beanFactory.freezeConfiguration();
// Instantiate all remaining (non-lazy-init) singletons.
// 这个就是最重要的方法:会把留下来的Bean们 不是lazy懒加载的bean都实例化掉
// bean真正实例化的时刻到了
beanFactory.preInstantiateSingletons();
}
@Override
public void freezeConfiguration() {
this.configurationFrozen = true;
this.frozenBeanDefinitionNames = StringUtils.toStringArray(this.beanDefinitionNames);
}
接下来重点看看DefaultListableBeanFactory#preInstantiateSingletons:实例化所有剩余的单例Bean。
@Override
public void preInstantiateSingletons() throws BeansException {
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
// 此处目的,把所有的bean定义信息名称,赋值到一个新的集合中
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
//getMergedLocalBeanDefinition:见下~
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 不是抽象类&&是单例&&不是懒加载
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 这是Spring提供的对工程bean模式的支持:比如第三方框架的继承经常采用这种方式
// 如果是工厂Bean,那就会此工厂Bean放进去
if (isFactoryBean(beanName)) {
// 拿到工厂Bean本省,注意有前缀为:FACTORY_BEAN_PREFIX
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
} else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
// true:表示渴望马上被初始化的,那就拿上执行初始化~
if (isEagerInit) {
getBean(beanName);
}
}
} else { // 这里,就是普通单例Bean正式初始化了~ 核心逻辑在方法:doGetBean
// 关于doGetBean方法的详解:下面有贴出博文,专文讲解
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
// SmartInitializingSingleton:所有非lazy单例Bean实例化完成后的回调方法 Spring4.1才提供
//SmartInitializingSingleton的afterSingletonsInstantiated方法是在所有单例bean都已经被创建后执行的
//InitializingBean#afterPropertiesSet 是在仅仅自己被创建好了执行的
// 比如EventListenerMethodProcessor它在afterSingletonsInstantiated方法里就去处理所有的Bean的方法
// 看看哪些被标注了@EventListener注解,提取处理也作为一个Listener放到容器addApplicationListener里面去
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
// 比如:ScheduledAnnotationBeanPostProcessor CacheAspectSupport MBeanExporter等等
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
此处必须说明:此处绝大部分的单例Bean定义信息都会被实例化,但是如果是通过FactoryBean定义的,它是懒加载的(如果没人使用,就先不会实例化。只会到使用的时候才实例化~)。如下例子:
@Configuration
public class RootConfig {
@Bean
public Person person() {
System.out.println("this is from @Bean person");
return new Person();
}
@Bean("personFactoryBean")
public FactoryBean<Person> personFactoryBean() {
return new FactoryBean<Person>() {
@Override
public Person getObject() throws Exception {
System.out.println("this is from personFactoryBean");
return new Person();
}
@Override
public Class<?> getObjectType() {
return Person.class;
}
};
}
}
默认情况下,person()会被启动时候,实例化,但是personFactoryBean()不会。
此时通过applicationContext.getBeanDefinitionNames()能找到personFactoryBean这个Bean定义。并且通过.beanFactory.getSingletonNames()也能找到personFactoryBean这个单例Bean,所以其实此时容器内的Bean是FactoryBean而不是真正的Bean,只有在真正使用的时候,才会create一个真正的Bean出来~
比如我只需要在某个组件内注入一下:
@Autowired
@Qualifier("personFactoryBean")
private Person person;
这个FactoryBean#getObject就会立马执行了~
getMergedLocalBeanDefinition方法
这里先解释一下getMergedLocalBeanDefinition方法的含义,因为这个方法会常常看到。
Bean定义公共的抽象类是AbstractBeanDefinition,普通的Bean在Spring加载Bean定义的时候,实例化出来的是GenericBeanDefinition,而Spring上下文包括实例化所有Bean用的。
AbstractBeanDefinition是RootBeanDefinition,这时候就使用getMergedLocalBeanDefinition方法做了一次转化,将非RootBeanDefinition转换为RootBeanDefinition以供后续操作。
// 该方法功能说明:在map缓存中把Bean的定义拿出来。交给getMergedLocalBeanDefinition处理。最终转换成了RootBeanDefinition类型
//在转换的过程中如果BeanDefinition的父类不为空,则把父类的属性也合并到RootBeanDefinition中,
//所以getMergedLocalBeanDefinition方法的作用就是获取缓存的BeanDefinition对象并合并其父类和本身的属性
//注意如果当前BeanDefinition存在父BeanDefinition,会基于父BeanDefinition生成一个RootBeanDefinition,然后再将调用OverrideFrom子BeanDefinition的相关属性覆写进去
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
// Quick check on the concurrent map first, with minimal locking.
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
if (mbd != null) {
return mbd;
}
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
getBeanDefinition(beanName):方法如下
// 这一步说白了:就是把前面已经保存在IOC容器里的BeanDefinition定义信息
@Override
public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
BeanDefinition bd = this.beanDefinitionMap.get(beanName);
if (bd == null) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("No bean named '" + beanName + "' found in " + this);
}
throw new NoSuchBeanDefinitionException(beanName);
}
return bd;
}
getBean():创建Bean的核心方法
getBean()方法为创建Bean,包括初始化剩余的单实例Bean时候的核心方法。
至此,finishBeanFactoryInitialization这一步完成,所有的单例Bean已经创建完成并放置容器里。
refresh() 第十二步:finishRefresh()
refresh做完之后需要做的其他事情。
protected void finishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning).
// 这个是Spring5.0之后才有的方法
// 表示清除一些resourceCaches,如doc说的 清楚context级别的资源缓存,比如ASM的元数据
clearResourceCaches();
// Initialize lifecycle processor for this context.
// 初始化所有的LifecycleProcessor 详见下面
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
// 上面注册好的处理器,这里就拿出来,调用它的onRefresh方法了
getLifecycleProcessor().onRefresh();
// Publish the final event.
// 发布容器刷新的事件:
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
// 和MBeanServer和MBean有关的。相当于把当前容器上下文,注册到MBeanServer里面去。
// 这样子,MBeanServer持久了容器的引用,就可以拿到容器的所有内容了,也就让Spring支持到了MBean的相关功能
LiveBeansView.registerApplicationContext(this);
}
initLifecycleProcessor()
方法开始生命周期,并在Spring关闭的时候调用 stop方法来结束生命周期,通常用来配置后台程序,在启动后一直运行(如对 MQ 进行轮询等)。而ApplicationContext的初始化最后正是保证了这一功能的实现。
当ApplicationContext启动或停止时,它会通过LifecycleProcessor来与所有声明的bean的周期做状态更新,而在LifecycleProcessor使用前首先需要初始化。
// 这个初始化逻辑比较简单
protected void initLifecycleProcessor() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 如果工厂里已经存在LifecycleProcessor,那就拿出来,把值放上去this.lifecycleProcessor
if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
this.lifecycleProcessor = beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
}
// 一般情况下,都会注册上这个默认的处理器DefaultLifecycleProcessor
else {
DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
defaultProcessor.setBeanFactory(beanFactory);
this.lifecycleProcessor = defaultProcessor;
// 直接注册成单例Bean进去容器里
beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
}
}
初始化生命周期处理器,并设置到Spring容器中(LifecycleProcessor)
调用生命周期处理器的onRefresh方法,这个方法会找出Spring容器中实现了SmartLifecycle接口的类并进行start方法的调用
发布ContextRefreshedEvent事件告知对应的ApplicationListener进行响应的操作
调用LiveBeansView的registerApplicationContext方法:如果设置了JMX相关的属性,则就调用该方法
发布EmbeddedServletContainerInitializedEvent事件告知对应的ApplicationListener进行响应的操作
getLifecycleProcessor().onRefresh():DefaultLifecycleProcessor
LifecycleProcessor作为一个Bean,它自己也实现了Lifecycle这个接口。LifecycleProcessor和DefaultLifecycleProcessor都是Spring3.0提供的,Lifecycle在Spring2.0就有了,但子接口SmartLifecycle是Spring3.0后提供的。
public interface LifecycleProcessor extends Lifecycle {}
public interface SmartLifecycle extends Lifecycle, Phased {
// 是否伴随这容器的启动而启动 true表示容器refreshed它就会启动了
// false:必须显示的执行了它的start()才行
boolean isAutoStartup();
// 相比于Lifecycle 的stop,增加了回调函数
void stop(Runnable callback);
}
public interface Phased {
// 权重值
int getPhase();
}
这里的处理器(只能有一个),就是我们上面注册好了的DefaultLifecycleProcessor,我们看看它的主要方法:
(1)启动和关闭调用的顺序是很重要的。如果两个对象之间存在依赖关系,依赖类要在其依赖类后启动,依赖类也要在其依赖类前停止。
// Lifecycle的方法
@Override
public void start() {
// 传false,表示Bean一定会启动
startBeans(false);
this.running = true;
}
@Override
public void stop() {
stopBeans();
this.running = false;
}
@Override
public boolean isRunning() {
return this.running;
}
// LifecycleProcessor的方法
//getLifecycleProcessor().onRefresh(); 这个方法才是容器启动时候自动会调用的,其余都不是
// 显然它默认只会执行实现了SmartLifecycle接口并且isAutoStartup = true的Bean的start方法
@Override
public void onRefresh() {
startBeans(true);
this.running = true;
}
// 容器关闭的时候自动会调的
@Override
public void onClose() {
stopBeans();
this.running = false;
}
// 而到底bean实现的Lifecyle的start()、stop()方法是否会调用呢? 请看下文
//======================startBeans和stopBeans LifecycleGroup#start======================
// autoStartupOnly:是否仅支持自动启动
// true:只支持伴随容器启动 (bean必须实现了`SmartLifecycle`接口且isAutoStartup为true才行)
// false:表示无所谓。都会执行bean的start方法=======
private void startBeans(boolean autoStartupOnly) {
//拿到所有的实现了Lifecycle/SmartLifecycle的 已经在IOC容器里面的单例Bean们(备注:不包括自己this,也就是说处理器自己不包含进去)
// 这里若我们自己没有定义过实现Lifecycle的Bean,这里就是空的
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
// phases 这个Map,表示按照phase 值,吧这个Bean进行分组,最后分组执行
Map<Integer, LifecycleGroup> phases = new HashMap<>();
lifecycleBeans.forEach((beanName, bean) -> {
// 若Bean实现了SmartLifecycle 接口并且标注是AutoStartup 或者 强制要求自动自行的autoStartupOnly = true
if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
int phase = getPhase(bean);
LifecycleGroup group = phases.get(phase);
if (group == null) {
group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
phases.put(phase, group);
}
// 添加到phase 值相同的组 分组嘛
group.add(beanName, bean);
}
});
if (!phases.isEmpty()) {
List<Integer> keys = new ArrayList<>(phases.keySet());
// 此处有个根据key从小到大的排序,然后一个个的调用他们的start方法
Collections.sort(keys);
for (Integer key : keys) {
// 这里调用LifecycleGroup#start() 如下
phases.get(key).start();
}
}
}
//LifecycleGroup#start()
public void start() {
if (this.members.isEmpty()) {
return;
}
if (logger.isInfoEnabled()) {
logger.info("Starting beans in phase " + this.phase);
}
// 按照权重值进行排序 若没有实现Smart接口的 权重值都为0
Collections.sort(this.members);
for (LifecycleGroupMember member : this.members) {
if (this.lifecycleBeans.containsKey(member.name)) {
// 一次执行这些Bean的start方法(这里面逻辑就没啥好看的,只有一个考虑到getBeanFactory().dependenciesForBean控制Bean的依赖关系的)
doStart(this.lifecycleBeans, member.name, this.autoStartupOnly);
}
}
}
//stopBeans原理基本同startBeans,只是顺序是倒序的,此处省略
就这样,实现了Lifecycle接口的Bean start方法什么时候调用就有门路了。
从上面的源码中,我们能够读出什么异常的地方呢?我们发现Lifecycle这个接口并不能直接使用。因为DefaultLifecycleProcessor的onRefresh方法传值为autoStartupOnly=true:表示只有实现了SmartLifecycle的Bean才会调用start方法,因为实现了SmartLifecycle接口会有一个phase值,根据上面源码会根据此值分组执行。
autoStartupOnly=false则只要是Lifecycle 的实现既可以被调用,我们会给其默认的phase。
所以,我们要想要这个功能,请实现SmartLifecycle,而不是Lifecycle接口
结论
- Spring的IoC容器启动过程中,默认只会执行实现了SmartLifecycle接口且isAutoStartup()=true的Bean的start()方法的。(所以你要想容器启动后就执行,请实现SmartLifecycle吧)
- AbstractApplicationContext#start() 手动调用触发。常见的一般这么做的:
context = new ClassPathXmlApplicationContext(configPath.split("[,\\s]+"));
context.start();
调用container这个方法后,则会将启动信号扩散至该容器内部的所有组件。会调用【所有】的实现了Lifecycle的组件的start()方法~~~
当然,我们稍作处理,也能让Lifecycle生效。当然,我并不建议这么去做~~~~~~~~~
// 注意,此处的名称必须,必须是lifecycleProcessor 否则没有效果的
// 名称也可以用这个常量AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME
@Component("lifecycleProcessor")
public class MinivisionDefaultLifecycleProcessor extends DefaultLifecycleProcessor {
/**
* 这边重写了onRefresh方法 让其去调用start()方法,而start方法上面我们能看得见,它传的false
*/
@Override
public void onRefresh() {
super.start();
}
}
还有一个方式就是我们获取到容器后显示的调用start方法。但是这两种方式,我个人都不推荐这么去做~~~
publishEvent(new ContextRefreshedEvent(this)):发布容器刷新的事件
//由此我们可以看到,ApplicationContext容器也是有发布事件的能力的(事件为:ApplicationEvent或其子类)
@Override
public void publishEvent(ApplicationEvent event) {
publishEvent(event, null);
}
// 本方法Spring4.2之后才有 属于发布事件的方法
// 这个方法更强:它能发布所有的事件,事件源是Object嘛
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
// Decorate event as an ApplicationEvent if necessary
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
// 最终也会被包装成applicationEvent的事件类型,带有一个Payload而已
else {
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType();
}
}
// Multicast right now if possible - or lazily once the multicaster is initialized
// 如果早期事件已经被初始化了,那就先放进早期事件里,否则esle那里,就直接发送事件了
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
} else {
//拿到多播器,发送这个时间
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// Publish event via parent context as well...
// 这里注意:如果存在父容器,那也给父容器会发送一个事件
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
} else {
this.parent.publishEvent(event);
}
}
}
完成了这一步骤后,Spring IOC容器正式启动成功了。
优雅的关闭Spring容器
关于关闭容器,是讨论得比较少的话题。确实,平时开发中,我们也可以不用太关心容器的关闭,暴力解决就行,因此这里也只简单的说一下,优雅的关闭Spring容器的方式。
先聊聊Runtime类
每个Java应用都有一个属于自己的Runtime类实例,使应用程序能够与其运行的环境相连接,可以通过 getRuntime 方法获取/销毁当前运行状态中的一些内容或者进行内存清理。应用程序不能创建自己Runtime 类实例。
它有一个API如下:Runtime.getRuntime().addShutdownHook(shutdownHook)
在Java应用程序中可以通过添加关闭钩子,实现在程序退出时关闭资源的功能。 使用Runtime.addShutdownHook(Thread hook)向JVM添加关闭钩子。
这句代码可以书写在任何地方,总之就是JVM退出的时候才会去调用这个钩子Thread~
触发场景
- 程序正常退出
- 使用System.exit()
- 终端使用Ctrl+C触发的中断
- 系统关闭
- 使用Kill pid命令干掉进程(kill -9除外)
以下场景不会触发
- 在Eclipse/idea中直接点击Terminate关闭程序时不会触发关闭钩子的;
- 在Linux下使用kill -9也是不会触发钩子的;
知了这个钩子后,我们就可以在关闭线程里,做一些优雅的释放资源事情了。
有了以上知识,我们再看看Spring场景下怎么优雅的关闭:
(1)Web应用
如果我们正常的关闭Tomcat,是能够正常的关闭web容器的同时,关闭Spring容器的。因此内部细节,我们此处不关心了。
(2)非web应用(比如纯dubbo应用)
我们看看AbstractApplicationContext类里其实提供了实现方法:
@Override
public void registerShutdownHook() {
if (this.shutdownHook == null) {
// No shutdown hook registered yet.
this.shutdownHook = new Thread() {
@Override
public void run() {
synchronized (startupShutdownMonitor) {
// 具体的容器管理逻辑
doClose();
}
}
};
Runtime.getRuntime().addShutdownHook(this.shutdownHook);
}
}
因此当我们启动容器的时候,自己调用registerShutdownHook这个方法便可,非常的方便。比如Dubbo框架,其实他就是这么优雅的去关闭容器的。
(3)Spring Boot环境优雅的关闭容器
当把打包好的jar包发布到服务器,并通过java -jar运行,一般要把springboot项目关闭大多数都是先找到项目的pid,然后直接kill pid,不过这种方法在特殊需求场景下不太合适(不安全),同时也不优雅。
方案一:使用actuator
开启端点
# 启用shutdown
management.endpoint.shutdown.enabled=true
# 公开所有的端点
management.endpoints.web.exposure.include=*
然后模拟发送一个POST请求:curl -X POST http://host:port/actuator/shutdown 即可优雅的关闭容器了。但是显然,这个危险系数太高了,万一ip和端口被别人知道了呢?
方案二:加固Endpoints
配置参考如下:
endpoints:
shutdown:
enabled: true
path: /xxx
management:
security:
enabled: true
port: 9001
address: 127.0.0.1
context-path: /admin
security:
basic:
enabled: true
path: /admin
user:
name: root
password: 123456
配置完成后,最终的停服命令为: (有了用户名、密码加持,可以说是能够达到生产级别的安全性了)
curl -X POST -u root:123456 http://127.0.0.1:9001/admin/xxx
方案三:注册为Linux系统服务
可以轻松地用 init.d 或 systemd 注册成 Linux/Unix 系统服务,这使得在生产环境中,安装和管理 SpringBoot 应用程序变得非常简单。
Spring容器的refresh()【创建、刷新】完整总结
1、prepareRefresh()刷新前的预处理;
0)、this.closed.set(false),this.active.set(true) 设置一些标记位
1)、initPropertySources()初始化一些属性设置;(交由子类去实现,比如web容器中的 AbstractRefreshableWebApplicationContext 就去初始化了servlet的一些init参数等等)
2)、getEnvironment().validateRequiredProperties();检验属性的合法等
3)、earlyApplicationEvents= new LinkedHashSet<ApplicationEvent>();初始化容器,保存一些早期的事件;
2、obtainFreshBeanFactory();获取BeanFactory;
1)、refreshBeanFactory();抽象方法,子类【AbstractRefreshableApplicationContext】唯一实现的:
①、若已经存在beanFactory了,那就做一些清理工作(销毁单例Bean、关闭工厂)
②、创建了一个this.beanFactory = new DefaultListableBeanFactory();并且设置id
③、把旧的工厂的属性赋值给新创建的工厂:customizeBeanFactory(beanFactory)
④、loadBeanDefinitions(beanFactory):加载Bean定义。抽象方法,由子类去决定从哪儿去把Bean定义加载进来,实现有比如:
XmlWebApplicationContext:专为web设计的从xml文件里加载Bean定义(借助XmlBeanDefinitionReader)
ClassPathXmlApplicationContext/FileSystemXmlApplicationContext:均由父类AbstractXmlApplicationContext去实现这个方法的,也是借助XmlBeanDefinitionReader
AnnotationConfigWebApplicationContext:基于注解驱动的容器。(也是当下最流行、最重要的一个实现,前面一篇博文对此有重点分析),借助了AnnotatedBeanDefinitionReader.register()方法加载Bean定义
(这里面需要注意的是:.register()只是把当前这一个Class对象registry.registerBeanDefinition()了,至于内部的@Bean、@ComponentScan扫描到的,都不是在此处注册的)
有必要说一句:AnnotationConfigApplicationContext是在非web环境下的容器。它虽然没有实现实现loadBeanDefinitions()抽象方法,是因为它在new对象的时候,已经调用了.register()完成配置Bean定义信息的注册了
2)、getBeanFactory();返回刚才GenericApplicationContext创建的BeanFactory对象;
3)、将创建的BeanFactory【DefaultListableBeanFactory】返回;
=======到这一步截止,BeanFactory已经创建好了(只不过都还是默认配置而已),配置Bean的定义信息也注册好了=======
3、prepareBeanFactory(beanFactory);BeanFactory的预准备工作(对BeanFactory进行一些设置);
1)、设置BeanFactory的类加载器、StandardBeanExpressionResolver、ResourceEditorRegistrar
2)、添加感知后置处理器BeanPostProcessor【ApplicationContextAwareProcessor】,并设置一些忽略EnvironmentAware、EmbeddedValueResolverAware、xxxxx(因为这个处理器都一把抓了)
3)、注册【可以解析的(表示虽然不在容器里,但还是可以直接 @Auwowired)】自动装配;我们能直接在任何组件中自动注入(@Autowired):
BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext
5)、添加BeanPostProcessor【ApplicationListenerDetector】 检测注入进来的Bean是否是监听器
6)、Detect a LoadTimeWeaver and prepare for weaving, if found.添加编译时的AspectJ支持:LoadTimeWeaverAwareProcessor
(添加的支持的条件是:beanFactory.containsBean("loadTimeWeaver"))
7)、给BeanFactory中注册一些能用的组件;
environment-->【ConfigurableEnvironment】、
systemProperties-->【Map<String, Object>】、
systemEnvironment-->【Map<String, Object>】
4、postProcessBeanFactory(beanFactory);BeanFactory准备工作完成后进行的后置处理工作;(由子类完成)
一般web容器都会对应的实现此方法,比如 AbstractRefreshableWebApplicationContext:
1)、添加感知BeanPostProcessor【ServletContextAwareProcessor】,支持到了ServletContextAware、ServletConfigAware
2)、注册scopse:beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());当然还有SCOPE_SESSION、SCOPE_APPLICATION
3)、向上线一样,注册【可以解析的】自动注入依赖:ServletRequest/ServletResponse/HttpSession/WebRequest
(备注:此处放进容器的都是xxxObjectFactory类型,所以这是为何@Autowired没有线程安全问题的重要一步)
4)、registerEnvironmentBeans:注册环境相关的Bean(使用的registerSingleton,是直接以单例Bean放到容器里面了)
servletContext-->【ServletContext】
servletConfig-->【ServletConfig】
contextParameters-->【Map<String, String>】 保存有所有的init初始化参数(getInitParameter)
contextAttributes-->【Map<String, Object>】 servletContext的所有属性(ServletContext#getAttribute(String))
========以上是BeanFactory的创建及预准备工作,至此准备工作完成了,那么接下来就得利用工厂干点正事了========
5、invokeBeanFactoryPostProcessors(beanFactory);执行BeanFactoryPostProcessor的方法;
BeanFactoryPostProcessor:BeanFactory的后置处理器。此处调用,现在就表示在BeanFactory标准初始化之后执行的;
两个接口:BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor(子接口)
1)、执行BeanFactoryPostProcessor们的方法;
===先执行BeanDefinitionRegistryPostProcessor===
1)、获取所有的BeanDefinitionRegistryPostProcessor;(当然会最先执行我们手动set进去的Processor,但是这个一般都不会有)
2)、先执行实现了PriorityOrdered优先级接口的BeanDefinitionRegistryPostProcessor、
postProcessor.postProcessBeanDefinitionRegistry(registry)
3)、在执行实现了Ordered顺序接口的BeanDefinitionRegistryPostProcessor
4)、最后执行没有实现任何优先级或者是顺序接口的BeanDefinitionRegistryPostProcessors
(小细节:都会调用getBean(“name”,BeanDefinitionRegistryPostProcessor.class)方法,所以都会先实例化,才去执行的)
**这里面需要特别的介绍一个处理器:`ConfigurationClassPostProcessor`,它是一个BeanDefinitionRegistryPostProcessor**
**它会解析完成所有的@Configuration配置类,然后所有@Bean、@ComponentScan等等Bean定义都会搜集进来了,所以这一步是非常的重要的**
===再执行BeanFactoryPostProcessor的方法(顺序逻辑同上,略)===
2)、再次检测一次添加对AspectJ的支持。为何还要检测呢?through an @Bean method registered by ConfigurationClassPostProcessor,这样我们注入了一个切面Bean,就符合条件了嘛
6、registerBeanPostProcessors(beanFactory);注册BeanPostProcessor(Bean的后置处理器)【 intercept bean creation】
**不同接口类型的BeanPostProcessor;在Bean创建前后的执行时机是不一样的**
BeanPostProcessor:BeanPostProcessor是一个工厂钩子,允许Spring框架在新创建Bean实例时对其进行定制化修改,比如填充Bean、创建代理、解析Bean内部的注解等等。。。
DestructionAwareBeanPostProcessor:Bean销毁时候
InstantiationAwareBeanPostProcessor:Bean初始化的时候
SmartInstantiationAwareBeanPostProcessor:初始化增强版本:增加了一个对Bean类型预测的回调(一般是Spring内部使用,调用者还是使用InstantiationAwareBeanPostProcessor就好)
MergedBeanDefinitionPostProcessor:合并处理Bean定义的时候的回调【该类型的处理器保存在名为internalPostProcessors的List中】、
1)、获取所有的 BeanPostProcessor;后置处理器都默认可以通过PriorityOrdered、Ordered接口来执行优先级
2)、先注册PriorityOrdered优先级接口的BeanPostProcessor;
把每一个BeanPostProcessor;添加到BeanFactory中
beanFactory.addBeanPostProcessor(postProcessor);
3)、再注册Ordered接口的、最后注册没有实现任何优先级接口的、最终注册MergedBeanDefinitionPostProcessor
(此处细节:BeanPostProcessor本身也是一个Bean,其注册之前一定先实例化,而且是分批实例化和注册。
另外还有一个非常非常重要的一点就是阶段顺序问题:
我们可以把BeanPostProcessor的实例化与注册分为四个阶段:
第一阶段applicationContext内置阶段、
第二阶段priorityOrdered阶段、
第三阶段Ordered阶段、
第四阶段nonOrdered阶段
因为是分批注册,所以我们同阶段是不能拦截到同阶段的BeanPostProcessor的实例化的。举例子:
PriorityOrdered的只能被内置阶段的比如:ApplicationContextAwareProcessor(可以注入啦)/ApplicationListenerDetector(可以接受事件啦)这种拦截
而:Ordered就可以被 内置的、PriorityOrdered都拦截到了
。。。 以此类推。。。
所以我们的BeanPostProcessor是可以@Autowired 比如Service、Dao来做一些事的。单思,但是一定要【注意避免BeanPostProcessor启动时的“误伤”陷阱】,什么意思?大概解释一下如下:
可能由于你的Processor依赖于某个@Bean,从而让它提前实例化了,然后就很可能错过了后面一些BeanPostProcessor的处理,造成“误伤”
(SpringBoot中使用Shiro、Spring-Cache的时候,使用不当会出现这样的问题)
6)、这一步非常有意思:moving it to the end of the processor chain。它的又注册了一次,作用是把这个探测器移动到处理器的底部,最后一个(显然,最后一个是为了不要放过任何Bean)
(小细节:可能有小伙伴疑问,这里也是new出来,这这样容器内不就有两个探测器对象了吗?气其实不然,ApplicationListenerDetector它重写了hashCode方法,且只和应用applicationContext有关)
return ObjectUtils.nullSafeHashCode(this.applicationContext);所以对它执行remove的时候,会被当作同一个对象处理,能把老的移除成功添加新的的
7、initMessageSource();初始化MessageSource组件(做国际化功能;消息绑定,消息解析)
1)、看容器中是否有id为messageSource的,类型是MessageSource的组件
如果有赋值给messageSource,如果没有自己创建一个DelegatingMessageSource;
MessageSource:取出国际化配置文件中的某个key的值;能按照区域信息获取;
2)、把创建好的MessageSource注册在容器中,以后获取国际化配置文件的值的时候,可以自动注入MessageSource
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource)
8、initApplicationEventMulticaster();初始化事件派发器;
1)、从BeanFactory中获取applicationEventMulticaster的ApplicationEventMulticaster;
2)、如果上一步没有配置;创建一个SimpleApplicationEventMulticaster,将创建的ApplicationEventMulticaster添加到BeanFactory中
9、onRefresh();留给子容器(子类) 容器刷新的时候做些事
AbstractRefreshableWebApplicationContext:this.themeSource = UiApplicationContextUtils.initThemeSource(this);
10、registerListeners();把容器中将所有项目里面的ApplicationListener注册进来;
1、拿到容器里所有的Bean定义的名字,类型为ApplicationListener,然后添加进来
getApplicationEventMulticaster().addApplicationListener(listener);
2、派发之前步骤产生的事件(早期事件)
(细节:此处只是把Bean的名字放进去,Bean还没有实例化哦~~~~)
11、finishBeanFactoryInitialization(beanFactory);初始化所有剩下的单实例bean;这应该是最核心的一步了
1)、为容器初始化ConversionService(容器若没有就不用初始化了,依然采用getBean()初始化的) 提供转换服务
2)、若没有设置值解析器,那就注册一个默认的值解析器(lambda表示的匿名处理)
3)、实例化LoadTimeWeaverAware(若存在)
4)、清空临时类加载器:beanFactory.setTempClassLoader(null)
5)、缓存(快照)下当前所有的Bean定义信息 beanFactory.freezeConfiguration();
==== 更精确的是说是根据Bean的定义信息:beanDefinitionNames来实例化、初始化剩余的Bean ====
6)、beanFactory.preInstantiateSingletons();初始化后剩下的单实例bean(过程这里就不详说了)
12、finishRefresh();完成BeanFactory的初始化创建工作;IOC容器就创建完成
0)、clearResourceCaches(); (Spring5.0才有)
1)、initLifecycleProcessor();初始化和生命周期有关的后置处理器;从容器中找是否有lifecycleProcessor的组件【LifecycleProcessor】;如果没有new DefaultLifecycleProcessor();
关于Lifecycle接口的使用,也专门讲解过,这里不聊了
2)、getLifecycleProcessor().onRefresh(); 相当于上面刚注册,下面就调用了
3)、publishEvent(new ContextRefreshedEvent(this));发布容器刷新完成事件;
4)、liveBeansView.registerApplicationContext(this); 和MBean相关,略
======总结===========
1)、Spring容器在启动的时候,先会保存所有注册进来的Bean的定义信息(可以有N种方式);
1)、xml注册bean;<bean>
2)、注解注册Bean;@Service、@Component、@Bean、xxx
2)、Spring容器会合适的时机创建这些Bean
1)、用到这个bean的时候;利用getBean创建bean;创建好以后保存在容器中;
2)、统一创建剩下所有的bean的时候;finishBeanFactoryInitialization();
3)、后置处理器;BeanPostProcessor
1)、每一个bean创建完成,都会使用各种后置处理器进行处理;来增强bean的功能;
AutowiredAnnotationBeanPostProcessor:处理自动注入
AnnotationAwareAspectJAutoProxyCreator:来做AOP功能;
xxx....
增强的功能注解:
AsyncAnnotationBeanPostProcessor
....
4)、事件驱动模型;
ApplicationListener;事件监听;
ApplicationEventMulticaster;事件派发:
总结
IoC的启动包括BeanDefinition的Resource定位、注入和注册三个基本过程。
第一个过程是Resource定位过程。这个Resource定位指的是BeanDefinition的资源定位,它由ResourceLoader通过统一的Resource接口来完成。
第二个过程是BeanDefinition的载入。这个载入过程是把用户定义好的Bean表示成IoC容器内部的数据结构,而这个容器内部的数据结构就是BeanDefinition。
第三个过程是向IoC容器注册这些BeanDefinition的过程。在IoC容器内部将BeanDefinition注入到一个HashMap中去,IoC容器就是通过这个HashMap来持有这些BeanDefinition数据的。
参考: |