Spring容器的创建刷新过程
Spring容器的创建刷新过程
以AnnotionConfigApplicationContext为例,在new一个AnnotionConfigApplicationContext的时候,其构造函数内就会调用父类的refresh方法
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses);
refresh();// <-- 调用AbstractApplicationContext的refresh方法
}
所以呢,Spring容器的创建过程主要在这个refresh方法里边。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1、Prepare this context for refreshing.
prepareRefresh();
///2、Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
///3、Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
//4、 Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
//5、 Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
//6、 Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
//7、 Initialize message source for this context.
initMessageSource();
//8、 Initialize event multicaster for this context.
initApplicationEventMulticaster();
//9、 Initialize other special beans in specific context subclasses.
onRefresh();
//10、 Check for listener beans and register them.
registerListeners();
//11、 Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
//12、 Last step: publish corresponding event.
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.
destroyBeans();
// Reset 'active' flag.
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...
resetCommonCaches();
}
}
}
我给源码的每一步都加了序号(1~12),下面来详细看看每一步都做了些什么。
1、prepareRefresh() 刷新前准备
设置一些状态标记,如启动时间startupDate,closed/active状态
initPropertySources() 设置init属性,此方法交给子类去实现
getEnvironment().validateRequiredProperties()
如果无Environment,则new StandardEnvironment()
再调用validateRequiredProperties() 校验参数
earlyApplicationEvents= new LinkedHashSet();保存容器中的一些早期的事件
2、obtainFreshBeanFactory() 获取BeanFactory
refreshBeanFactory() 刷新BeanFactory
在GenericApplicationContext的构造方法中new了一个DefaultListableBeanFactory
通过this.beanFactory.setSerializationId(getId());设置一个唯一的id
getBeanFactory() 返回刚才GenericApplicationContext创建的BeanFactory对象
3、prepareBeanFactory(beanFactory) BeanFactory的准备工作
设置BeanFactory的类加载器、表达式解析器【StandardBeanExpressionResolver】、ResourceEditorRegistrar
添加BeanPostProcessor【ApplicationContextAwareProcessor】
设置不需要自动装配的接口
包括【EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware】
注册可以解析的自动装配的接口
包括【BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext】
添加BeanPostProcessor【ApplicationListenerDetector】
添加AspectJ【类加载时织入LoadTimeWeaver】
给BeanFactory中注册一些能用的组件
environment【ConfigurableEnvironment】
systemProperties【Map<String, Object>】
systemEnvironment【Map<String, Object>】
4、postProcessBeanFactory(beanFactory) BeanFactory后置处理
子类通过重写这个方法来在BeanFactory创建并预准备完成以后做进一步的设置
到这里,BeanFactory的创建及后置处理工作就结束了
5、invokeBeanFactoryPostProcessors(beanFactory) 执行BeanFactory后置方法
BeanFactoryPostProcessors是BeanFactory的后置处理器,在BeanFactory标准初始化之后、全部bean信息都被加载,但是还没有被实例化的时候执行。
在invokeBeanFactoryPostProcessors方法中,主要处理2种类型的接口:
BeanDefinitionRegistryPostProcessor 和 BeanFactoryPostProcessor
■先执行BeanDefinitionRegistryPostProcessor的方法,过程如下:
获取所有实现了BeanDefinitionRegistryPostProcessor接口的class
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false)
先执行实现了PriorityOrdered优先级接口的BeanDefinitionRegistryPostProcessor
postProcessor.postProcessBeanDefinitionRegistry(registry)
同理,再执行实现了Order顺序接口的BeanDefinitionRegistryPostProcessor;最后执行其他实现了BeanDefinitionRegistryPostProcessor的
Configuration类中通过@Import(ImportBeanDefinitionRegistrar)引入的类就是在这里被调用registerBeanDefinitions方法的…【processor:ConfigurationClassPostProcessor】
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry)
■再执行BeanFactoryPostProcessor的方法,过程如下:
获取所有实现了BeanFactoryPostProcessor接口的class
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false)
先执行实现了PriorityOrdered优先级接口的BeanFactoryPostProcessor
postProcessor.postProcessBeanFactory(beanFactory)
同理,再执行实现了Order顺序接口的BeanFactoryPostProcessor;最后执行其他实现了BeanDefinitionRegistryPostProcessor的
6、registerBeanPostProcessors(beanFactory) 注册bean的后置处理器
获取所有实现了BeanPostProcessor接口的class
beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
把获取的类按照 是否实现了 PriorityOrdered、Ordered接口、及其他 分成3类
按照优先级依次调用
beanFactory.addBeanPostProcessor(postProcessor);
最后注册一个ApplicationListenerDetector
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
这个Detector的作用是:
在Bean创建完成后检查是否是ApplicationListener,如果是则加到context中applicationContext.addApplicationListener((ApplicationListener<?>) bean)
7、initMessageSource() 初始化MessageSource组件
MessageSource组件主要用来实现国际化、消息解析处理。
在initMessageSource中,首先看容器中是否有id为messageSource的,类型是MessageSource的组件。如果没有则new DelegatingMessageSource() 放进去。
后面在处理国际化时,可以注入MessageSource对象,然后使用如下代码进行国际化
String getMessage(String code, Object[] args, Locale locale)
8、initApplicationEventMulticaster() 初始化事件多波器
在此方法中,首选从BeanFactory中获取id为“applicationEventMulticaster”的ApplicationEventMulticaster。如果没有就new SimpleApplicationEventMulticaster(beanFactory)放进去。[多波器,有的也叫派发器]
9、onRefresh() 留给子类重写
10、registerListeners() 注册事件监听器
从容器中拿到所有的ApplicationListener
将每个监听器添加到事件多波器中
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName)
处理前面步骤留下的earlyApplicationEvents,earlyApplicationEvents在步骤1.4中初始化为空的LinkedHashSet
getApplicationEventMulticaster().multicastEvent(earlyEvent)
11、finishBeanFactoryInitialization(beanFactory) 初始化所有剩下的单实例bean
核心逻辑在beanFactory.preInstantiateSingletons()方法中。这里面做的事情主要有:
循环编译所有的beanNames,获取RootBeanDefinition
如果bean 不是抽象的,是单实例的,是懒加载
判断是否 是实现FactoryBean接口的Bean
如果是,先做一些处理,再调getBean
如果不是,则直接调用getBean(beanName)
getBean(beanName) –> doGetBean(name, null, null, false)
先获取缓存中保存的单实例Bean【singletonObjects.get(beanName)】。如果能获取到说明这个Bean之前被创建过(所有创建过的单实例Bean都会被缓存在ConcurrentHashMap<String, Object>(256)中)
如果缓存中获取不到,则开启下面的创建流程
先将bean标记为已创建 markBeanAsCreated(beanName)
获取Bean的定义信息RootBeanDefinition
获取当前Bean依赖的其他Bean[mbd.getDependsOn()],如果有则调用getBean()把依赖的Bean先创建出来
开启单实例Bean的创建流程 createBean(beanName, mbd, args)
准备重写的方法
尝试返回代理对象
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
执行InstantiationAwareBeanPostProcessor
先触发:postProcessBeforeInstantiation();
如果BeforeInstantiation有返回值,再接着执行postProcessAfterInitialization();如果resolveBeforeInstantiation返回的不为null,则bean就创建好了
前面resolveBeforeInstantiation返回的不为null,则返回该bean;为null接着调Object beanInstance = doCreateBean(beanName, mbdToUse, args);创建Bean【step5】
创建doCreateBean(beanName, mbdToUse, args)
创建instanceWrapper = createBeanInstance(beanName, mbd, args)
利用工厂方法 或 对象的构造器 创建出Bean实例
调用MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition(mbd, beanType, beanName);
给bean属性赋值 populateBean(beanName, mbd, instanceWrapper)
赋值前,拿到所有的InstantiationAwareBeanPostProcessor后置处理器,调用postProcessAfterInstantiation()
再拿到所有的InstantiationAwareBeanPostProcessor后置处理器,调用postProcessPropertyValues()
赋值 applyPropertyValues(beanName, mbd, bw, pvs);
为属性利用setter方法等进行赋值
初始化bean,调用initializeBean(beanName, exposedObject, mbd)
执行xxxAware方法 invokeAwareMethods(beanName, bean),包括【BeanNameAware\BeanClassLoaderAware\BeanFactoryAware】
执行Bean后置处理器的before方法 applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName) 循环调用 beanProcessor.postProcessBeforeInitialization(result, beanName)
执行bean的初始化方法 invokeInitMethods(beanName, wrappedBean, mbd);
执行bean的后置处理器的after方法 applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName) 循环调用 beanProcessor.postProcessAfterInitialization(result, beanName)
Spring的AOP注解实现原理:
@EnableAspectJAutoProxy引入了继承自AbstractAutoProxyCreator的AnnotationAwareAspectJAutoProxyCreator
在AbstractAutoProxyCreator中实现了postProcessAfterInitialization方法,在方法内调用wrapIfNecessary(bean, beanName, cacheKey)方法创建代理对象返回出去,后续放入容器的就是这个代理对象
注册bean的销毁方法 registerDisposableBeanIfNecessary(beanName, bean, mbd);
将bean加入到singletonObjects中
所有bean创建完之后,判断bean是否是SmartInitializingSingleton的实例。如果是,就执行afterSingletonsInstantiated()
12、finishRefresh() 容器创建完成
initLifecycleProcessor() 初始化和生命周期有关的后置处理器
默认从容器中找是否有lifecycleProcessor的组件【LifecycleProcessor】;如果没有new DefaultLifecycleProcessor();加入到容器;
执行onfresh方法
getLifecycleProcessor().onRefresh()
发布容器刷新完成事件
publishEvent(new ContextRefreshedEvent(this))
调用LiveBeansView.registerApplicationContext(this)
Spring容器的创建刷新过程的更多相关文章
- spring源码学习之:spring容器的applicationContext启动过程
Spring 容器像一台构造精妙的机器,我们通过配置文件向机器传达控制信息,机器就能够按照设定的模式进行工作.如果我们将Spring容器比喻为一辆汽车,可以将 BeanFactory看成汽车的发动机, ...
- Spring - Spring容器概念及其初始化过程
引言 工作4年多,做了3年的java,每个项目都用Spring,但对Spring一直都是知其然而不知其所以然.鄙人深知Spring是一个高深的框架,正好近期脱离加班的苦逼状态,遂决定从Spring的官 ...
- Spring容器的创建原理
1.new ioc容器(AnnotationConfigApplicationContext 注解ioc) 2.refresh()方法调用 2.1 prepareRefresh()刷新前的预处理 a: ...
- 【Spring】简述@Configuration配置类注册BeanDefinition到Spring容器的过程
概述 本文以SpringBoot应用为基础,尝试分析基于注解@Configuration的配置类是如何向Spring容器注册BeanDefinition的过程 其中主要分析了 Configuratio ...
- Spring学习笔记之 Spring IOC容器(一)之 实例化容器,创建JavaBean对象,控制Bean实例化,setter方式注入,依赖属性的注入,自动装配功能实现自动属性注入
本节主要内容: 1.实例化Spring容器示例 2.利用Spring容器创建JavaBean对象 3.如何控制Bean实例化 4.利用Spring实现bean属性sett ...
- Spring 容器
Spring提供了两个核心接口:BeanFactory和ApplicationContext,其中applicationContext是BeanFactory的子接口. 他们都可代表Spring容器, ...
- Spring 读书笔记-----使用Spring容器(一)
pring有两个核心接口:BeanFactory和ApplicationContext,其中ApplicationContext是BeanFactory的子接口.他们都可代表Spring容器,Spri ...
- (转)Spring 读书笔记-----使用Spring容器(一)
Spring有两个核心接口:BeanFactory和ApplicationContext,其中ApplicationContext是BeanFactory的子接口.他们都可代表Spring容器,Spr ...
- Spring容器
1.Spring简介: a)Spring春天 b)官网:https://spring.io c)设计理念:轮子理念,不要重复创造轮子: d)Spring可以被理解为一个容器,用于管理其他的框架: e) ...
随机推荐
- Alpha冲刺 - (4/10)
Alpha冲刺 - (4/10) Part.1 开篇 队名:彳艮彳亍团队 组长博客:戳我进入 作业博客:班级博客本次作业的链接 Part.2 成员汇报 组员1(组长)柯奇豪 过去两天完成了哪些任务 ...
- OC 中property的使用
property在使用的时候需要在其前面加上@符号,需要将其写在类的头文件中 当在定义一个对象的属性变量时,例如定义一个Person类中的name属性,可定义为: @property (nonatom ...
- Windows 远程栈溢出挖掘与利用
缓冲区溢出攻击很容易被攻击者利用,因为 C 和 C++等语言并没有自动检测缓冲区溢出操作,同时程序编写人员在编写代码时也很难始终检查缓冲区是否可能溢出.利用溢出,攻击者可以将期望数据写入漏洞程序内存中 ...
- Java学习笔记42(序列化流)
对象中的数据,以流的形式,写入到文件中保存 过程称为写出对象,对象的序列化 ObjectOutputStream将对象写到文件中,实现序列化 在文件中,以流的形式,将对象读取出来, 读取对象,对象的反 ...
- Shell - 简明Shell入门14 - 操作符(Operator)
示例脚本及注释 #!/bin/bash echo "No code, just some comments." # ### 通配符 # * 代表任意(0个或多个)字符 # ? 代表 ...
- window7利用Nexus搭建maven私有服务器
下载地址 https://www.sonatype.com/oss-thank-you-win64.zip: cmd管理员运行命令 nexus.exe/install Nexus Service:(n ...
- jQuery事件委托
jQuery事件委托 <ul id="ulBox"> <li data-id="1"></li> <li data-i ...
- 安装CDH5 hadoop2.3.0 NodeManager 没有启动
今天在安装hadoop后,启动start-yarn.sh后,nodemanager起不起来,后来查看DN节点的日志,报了以下一个错误: FATAL org.apache.hadoop.yarn.ser ...
- Eclipse 项目导入 Android Studio 导致的乱码问题
最近有一个 Eclipse 项目导入 Android Studio 1.4 时出现乱码,Build 提示 Error:(38, 5) 閿欒: 缂栫爜UTF-8鐨勪笉鍙槧灏勫瓧绗?. 源代码是 GB ...
- walle多渠道打包+Tinker(bugly)热更新集成+360加固(乐固)
这三个东东是干啥的相信大家都有所耳闻了,如果你没有听说过,请出门左拐,百度一下你就知道.这里不对这三个东东具体的集成方式做详细的介绍,因为官方文档已经写的很详细了,主要是对同时使用这三个东东时所需要注 ...