当前位置:网站首页>解读 refresh 十二步骤
解读 refresh 十二步骤
2022-08-03 06:00:00 【流楚丶格念】
解读refresh
- refresh()
- 1. prepareRefresh
- 2. obtainFreshBeanFactory
- 3. prepareBeanFactory
- 4. postProcessBeanFactory
- 5. invokeBeanFactoryPostProcessors(beanFactory);
- 6. registerBeanPostProcessors(beanFactory);
- 7. initMessageSource();
- 8. initApplicationEventMulticaster();
- 9. onRefresh();
- 10. registerListeners();
- 11. finishBeanFactoryInitialization(beanFactory);
- 12. finishRefresh();
refresh()
refresh()方法代码如下:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备此上下文以进行刷新
prepareRefresh();
// 告诉子类刷新内部 bean 工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 准备在此上下文中使用的 bean 工厂
prepareBeanFactory(beanFactory);
try {
// 允许在上下文子类中对 bean 工厂进行后处理
postProcessBeanFactory(beanFactory);
// 调用在上下文中注册为 bean 的工厂处理器
invokeBeanFactoryPostProcessors(beanFactory);
// 注册 拦截 bean创建的 bean 处理器
registerBeanPostProcessors(beanFactory);
// 初始化此上下文的消息源
initMessageSource();
// 为此上下文初始化事件多播器
initApplicationEventMulticaster();
// 初始化特定上下文子类中的其他特殊bean
onRefresh();
// 检查监听器 bean 并注册它们
registerListeners();
// 实例化所有剩余的(非惰性初始化)单例。
finishBeanFactoryInitialization(beanFactory);
// 最后一步:发布相应的事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已经创建的单例以避免悬空资源
destroyBeans();
// 重置“活动”标志。
cancelRefresh(ex);
// 将异常传播给调用者
throw ex;
}
finally {
// 重置 Spring 核心中的公共自省缓存,因为我们可能不再需要单例 bean 的元数据...re...
resetCommonCaches();
}
}
}
首先是对上下文进行刷新:
// 准备此上下文以进行刷新
prepareRefresh();
1. prepareRefresh
创建和准备了 Environment 对象:
- Environment 的作用之一是为后续 @Value,值注入时提供键值
流程如下图所示:
prepareRefresh重点是准备了初始环境,我们跟进prepareRefresh源码实现:
可以看到获取环境配置的代码,继续跟进
里面创建了一个标准的环境:
我们在prepareRefresh();这打个断点也能看到里面的environment:
我们将第一步走完,可以看到environment被初始化成了StandardEnvironment
我们执行一个表达式测试一下:
比如说我们测试一下有没有JAVA_HOME的键值信息,我们发现是可以执行查询到的,所以说此时,一些系统的环境都已经加载到Spring中了:
我们将 展开可以看到JAVA环境变量和系统环境变量:
两个环境变量的内容如下:
我们也可以通过下面代码获取这两个环境变量
// 获取系统环境变量
System.getenv().keySet().stream().forEach(s -> System.out.println(s));
// java环境变量
System.getProperties().keySet().stream().forEach(s -> System.out.println(s));
同样,我们也可以使用StandardEnvironment获取这两个环境变量
StandardEnvironment env = new StandardEnvironment();
env.getSystemEnvironment().keySet().stream().forEach(s -> System.out.println(s));
env.getSystemProperties().keySet().stream().forEach(s -> System.out.println(s));
当然也可以加一个环境变量:
// 加一个环境变量
env.getPropertySources().addLast(new ResourcePropertySource("my",new ClassPathResource("1.properties")));
2. obtainFreshBeanFactory
获取(或创建)BeanFactory 来刷新 内部 bean 工厂:
- BeanFactory 的作用是负责 bean 的创建、依赖注入和初始化
- BeanDefinition 作为 bean 的设计蓝图,规定了 bean 的特征,如单例多例、依赖关系、初始销毁方法等
- BeanDefinition 的来源有多种多样,可以是通过 xml 获得、通过配置类获得、通过组件扫描获得,也可以是编程添加
ApplicationContext没有Bean初始化,依赖注入等功能他都没有,他得简介的调用BeanFactory 来对Bean进行管理,ApplicationContext委托给BeanFactory 来干这些活,ApplicationContext做的是扩展的活,Bean的核心功能是在BeanFactory 中。
执行流程如下:
我们继续跟进源码:
/** * 告诉子类刷新内部 bean 工厂。 * @return 新的 BeanFactory 实例 * @see #refreshBeanFactory() * @see #getBeanFactory() */
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
return getBeanFactory();
}
里面调用了接口中的两个方法:
/** * 子类必须实现此方法才能执行实际的配置加载。 * 该方法在任何其他初始化工作之前由 {@link #refresh()} 调用。 * <p>子类要么创建一个新的bean工厂并持有对它的引用, * 或返回它拥有的单个 BeanFactory 实例。在后一种情况下,它将 * 如果多次刷新上下文,通常会抛出 IllegalStateException。 * @throws BeansException 如果 bean 工厂的初始化失败 * @throws IllegalStateException 如果已经初始化并且多次刷新 * 不支持尝试 */
protected abstract void refreshBeanFactory() throw BeansException,IllegalStateException;
/** * 子类必须在此处返回其内部 bean 工厂。他们应该实施 * 高效查找,因此可以重复调用而不会降低性能。 * <p>注意:子类之前应该检查上下文是否仍然处于活动状态 * 返回内部 bean 工厂。内部工厂一般应该是 * 一旦上下文关闭,则认为不可用。 * @return 此应用程序上下文的内部 bean 工厂(从不 {@code null}) * @throws IllegalStateException 如果上下文还没有包含内部 bean 工厂 * (通常如果 {@link #refresh()} 从未被调用过)或者如果上下文已经 * 已经关闭 * @see #refreshBeanFactory() * @see #closeBeanFactory() */
@Override
公共抽象 ConfigurableListableBeanFactory getBeanFactory() throw IllegalStateException;
我们在这加个断点看看具体干了什么:
断点出我们执行下一步,看一下refreshBeanFactory的实现:
首先是一个Boolean,这个refreshed变量是用来判断有没有调用过refresh
给BeanFactory实现一个序列化id,这个就对于解读没啥大用了:
下面就是getBeanFactory方法:
这里直接返回了beanFactory
这是个啥?他之前创建过吗?怎么直接返回了?
这个其实在我们创建上下文时候就已经创建了,我们可以在GenericApplicationContext.java中找到答案:
在调用构造的时候就已经初始化beanFactory了
注意这里的ClassPathXmlApplicationContext上下文是调用的另一个refreshBeanFactory的实现
@Override protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
会用新的beanFactory覆盖旧的beanFactory
这里面实现获取BeanFactory 的方法是loadBeanDefinitions(beanFactory) ,下面来测试一下:
我们在xml中配置一个bean:
执行后可以看到加载了我们xml文件中的Bean,bean的所有信息都在value里
BeanDefinition测试(读取Bean方式)
1.xml方式读取
public class BeanDefinitionTest {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 1.xml方式读取
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions("classpath:app.xml");
System.out.println(reader.getBeanFactory());
}
}
得到从app.xml获取的bean
把这个常用的加到监控变量中:
2.组件扫描
加一个Bean3 添加 @Component
编写下面代码:
// 2.组件扫描
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(beanFactory);
scanner.scan("com.yyl.refresh");
执行可以看到Bean3加到了BeanFactory中:
(其他的是一些bean处理器的)
4.编程方式(Bean构建器)
// 4.编程方式添加
beanFactory.registerBeanDefinition("Bean4", BeanDefinitionBuilder.genericBeanDefinition(Bean4.class).getBeanDefinition());
编程方式比较可控,比如我们设置为多例:
// 4.编程方式添加
beanFactory.registerBeanDefinition("Bean4", BeanDefinitionBuilder
.genericBeanDefinition(Bean4.class)
.setScope("prototype")
.getBeanDefinition());
// 再打印一下
System.out.println(beanFactory.getBean("Bean4"));
System.out.println(beanFactory.getBean("Bean4"));
System.out.println(beanFactory.getBean("Bean4"));
结果如下,生成的是三个不同的对象:
再比如我们加一个初始化函数:
public class Bean4 {
public void initMethod(){
System.out.println("Bean init!!!");
}
}
// 4.编程方式添加
beanFactory.registerBeanDefinition("Bean4", BeanDefinitionBuilder
.genericBeanDefinition(Bean4.class)
.setScope("prototype")
.setInitMethodName("initMethod")
.getBeanDefinition());
System.out.println(beanFactory.getBean("Bean4"));
System.out.println(beanFactory.getBean("Bean4"));
System.out.println(beanFactory.getBean("Bean4"));
结果如下:
3. prepareBeanFactory
准备在此上下文中使用的 bean 工厂,完善BeanFactory,把一些重要的成员变量初始化:
- StandardBeanExpressionResolver 来解析 SpEL
- ResourceEditorRegistrar 会注册类型转换器,并应用 ApplicationContext 提供的 Environment 完成 ${ } 解析
- 特殊 bean 指 beanFactory 以及 ApplicationContext,通过 registerResolvableDependency 来注册它们
- ApplicationContextAwareProcessor 用来解析 Aware 接口
- ApplicationListenerDetector 用来识别容器中 ApplicationListener 类型的 bean
执行流程如下:
(右侧绿色表示初始化的)
下面我们追踪一下源码:
都是完善BeanFactory参数:
首先是要找到El解析器里的addPropertyEditorRegistrar:注册一组类型转化器
右键我们执行个语句测试一下这个注册器是干嘛滴:
执行找到我们Bean4的语句
beanFactory.getBeanExpressionResolver().evaluate("#{@Bean4}",new BeanExpressionContext(beanFactory,null))
发现是能查到我们刚注册的结果的:
可以,能解析EL表达式了
下面我们深入探究下里面的ResourceEditorRegistrar资源类型转化器,我们可以看到不同的资源类型用不同转化器转化
添加Bean后处理器:扩展功能
// Configure the bean factory with context callbacks.
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(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);
注册特殊类型对象:
// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
4. postProcessBeanFactory
这一步是空实现,留给子类扩展,做补充
- 一般 Web 环境的 ApplicationContext 都要利用它注册新的 Scope,完善 Web 下的 BeanFactory
- 体现的是模板方法设计模式
直接看源码:
首先我们可以看到确实是空实现:
/** * 按照标准修改应用上下文的内部bean工厂 * 初始化。所有 bean 定义都将被加载,但没有 bean * 将被实例化。这允许注册特殊的 * 某些 ApplicationContext 实现中的 BeanPostProcessors 等。 * @param beanFactory 应用上下文使用的bean工厂 */
protected postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}
来吧看看子类对他补充了啥吧,这里我们主要看一个web里对这个方法的实现:
没有的先要加一个依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
5. invokeBeanFactoryPostProcessors(beanFactory);
调用在上下文中注册的 BeanFactory 的后处理器:进一步完善BeanFactory
- beanFactory 后处理器,充当 beanFactory 的扩展点,可以用来补充或修改 BeanDefinition
- ConfigurationClassPostProcessor – 解析 @Configuration、@Bean、@Import、@PropertySource 等
- PropertySourcesPlaceHolderConfigurer – 替换 BeanDefinition 中的 ${ }
- MapperScannerConfigurer – 补充 Mapper 接口对应的 BeanDefinition
执行流程如下:
我们看一下源码:
首先他调用了配置后处理器的方法,具体实现太多,里面主要配置两个后处理器BeanDefinitionRegistryPostProcessor与BeanFactoryPostProcessor
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
下面我们来进行一个后处理器小测试
ConfigurationClassPostProcessor后处理器
新建一个测试类编写如下方法:
package com.yyl.refresh;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;
public class AppPostProcess {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("muConfig",MyConfig.class);
// context.registerBean("configurationClassPostProcessor", ConfigurationClassPostProcessor.class);
context.refresh();
System.out.println();
}
@Configuration
static class MyConfig{
public MyConfig(){
}
@Bean
public Bean1 bean1(){
return new Bean1();
}
@Bean
public Bean2 bean2(){
return new Bean2();
}
}
static class Bean1{
}
static class Bean2{
}
}
默认没有用到Bean1和Bean2,是不会主动加到BeanFactory中的
我们在第4步与第5步加一个断点,debug下:
我们看到只有一个我们注册的Bean:
当我们加上一个后处理器:ConfigurationClassPostProcessor
context.registerBean("configurationClassPostProcessor", ConfigurationClassPostProcessor.class);
再运行,当执行到第四步时,只有两个我们注册的Bean:
当执行完第五步,我们发现执行了后处理器的方法,把配置中的Bean也加到Bean工厂里来了
下面我们在使用@import测试下
@Configuration
@Import(Bean3.class)
static class MyConfig{
public MyConfig(){
}
@Bean
public Bean1 bean1(){
return new Bean1();
}
@Bean
public Bean2 bean2(){
return new Bean2();
}
}
static class Bean3{
}
重新Debug,可以看到Bean3也能通过后处理器加载进来
再加一个资源文件的注解
@Configuration
@Import(Bean3.class)
@PropertySource("classpath:1.properties")
static class MyConfig{
public MyConfig(){
}
@Bean
public Bean1 bean1(){
return new Bean1();
}
@Bean
public Bean2 bean2(){
return new Bean2();
}
}
运行,可以看到资源文件也能加载到环境当中
MapperScannerConfigurer后处理器
// mybatis后处理器
context.registerBean("mapperScannerConfigurer", MapperScannerConfigurer.class,bd -> {
// 找包名
bd.getPropertyValues().add("basePackage","com.yyl.mapper");
});
设置查找包下接口注入BeanFactory
// mybatis后处理器
context.registerBean("mapperScannerConfigurer", MapperScannerConfigurer.class,bd -> {
// 找包名
bd.getPropertyValues().add("basePackage","com.yyl.mapper");
// 找配置了@mapper注解的
bd.getPropertyValues().add("annotationClass","org.apache.ibatis.annotations.Mapper");
});
这回就只有roleMapper了
PropertySourcesPlaceholderConfigurer后处理器
解析${}的值
context.registerBean("propertySourcesPlaceholderConfigurer", PropertySourcesPlaceholderConfigurer.class);
测试一下,新增一个Bean4:
static class Bean4 {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
将${JAVA_HOME}设置到value上
context.registerBean("bean4",Bean4.class,bd -> {
bd.getPropertyValues().add("value","${JAVA_HOME}");
});
如果没加这个处理器是不能显示的
加上PropertySourcesPlaceholderConfigurer后处理器
context.registerBean("propertySourcesPlaceholderConfigurer", PropertySourcesPlaceholderConfigurer.class);
再运行没有问题:
6. registerBeanPostProcessors(beanFactory);
注册 bean创建的 bean 后处理器(在Bean的声明周期对Bean进行扩展)
- bean 后处理器,充当 bean 的扩展点,可以工作在 bean 的实例化、依赖注入、初始化阶段
- AutowiredAnnotationBeanPostProcessor 功能有:解析 @Autowired,@Value 注解
- CommonAnnotationBeanPostProcessor 功能有:解析 @Resource,@PostConstruct,@PreDestroy
- AnnotationAwareAspectJAutoProxyCreator 功能有:为符合切点的目标 bean 自动创建代理
三个处理器执行时机如下图所示:
执行流程如下:
beanDefinition中有没有Bean实现了PostProcess接口,有就说明不是一般的Bean是一个Bean后处理器,Spring把这中Bean实例化出来方法放到 beanPostProcess中
下面探究一下源码:
按照四组规定先后执行的Bean的顺序,
- 首先,注册实现 PriorityOrdered 的 BeanPostProcessor。
- 接下来,注册实现 Ordered 的 BeanPostProcessor。
- 现在,注册所有常规的 BeanPostProcessor。
- 最后,重新注册所有内部 BeanPostProcessor。
源码太多不贴了。
来看一个测试案例:
package com.yyl.refresh;
import org.springframework.context.support.GenericApplicationContext;
public class BeanPostProcess {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("bean1",Bean1.class);
context.registerBean("bean2",Bean2.class);
context.registerBean("bean3",Bean3.class);
context.refresh();
System.out.println(context.getBean(Bean1.class).bean2);
System.out.println(context.getBean(Bean1.class).bean3);
}
static class Bean1 {
private Bean2 bean2;
private Bean3 bean3;
}
static class Bean2 {
}
static class Bean3 {
}
}
这样打印是打印不出值的,因为他们之间还没有一个依赖注入关系
传统的依赖注入是这样的:
context.registerBean("bean1",Bean1.class,bd -> {
bd.getPropertyValues().add("bean2",new RuntimeBeanReference("bean2"));
bd.getPropertyValues().add("bean3",new RuntimeBeanReference("bean3"));
});
但是比较麻烦,我们可以用自动装配:
// 使用自动装配
context.registerBeanDefinition("bean1", BeanDefinitionBuilder
.genericBeanDefinition(Bean1.class)
.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME)
.getBeanDefinition());
还是麻烦,第三代出来了,@Autowired
@Autowired
private Bean2 bean2;
@Autowired
private Bean3 bean3;
诶!结果发现都没注入:
为啥呢? 这是因为咱们少了一个Bean的后处理器
加上后处理器
// Bean后处理器 @Autowire
context.registerBean("autowiredAnnotationBeanPostProcessor", AutowiredAnnotationBeanPostProcessor.class);
AutowiredAnnotationBeanPostProcessor处理器
支持什么注解?
这个答案我们从他源码的构造函数里可以找到,支持Spring标准注解 @Autowire和@Value
出这两个外,他还支持@Inject注解,这是官方的一个注解
作用1:探测候选构造
给Bean1加两个构造器
static class Bean1 {
private Bean2 bean2;
private Bean3 bean3;
public Bean1(Bean3 bean3) {
this.bean3 = bean3;
}
public Bean1(Bean2 bean2) {
this.bean2 = bean2;
}
public void setBean2(Bean2 bean2) {
this.bean2 = bean2;
}
public void setBean3(Bean3 bean3) {
this.bean3 = bean3;
}
}
使用AutowiredAnnotationBeanPostProcessor找出候选构造器
AutowiredAnnotationBeanPostProcessor beanPostProcessor = new AutowiredAnnotationBeanPostProcessor();
// 找候选构造器
Constructor<?>[] constructors = beanPostProcessor.determineCandidateConstructors(Bean1.class, "bean1");
System.out.println(Arrays.toString(constructors));
但是我们在构造器上没有加@Autowired他是找不到的
给Bean1的一个构造加上注解:
@Autowired
public Bean1(Bean2 bean2) {
this.bean2 = bean2;
}
我们把其中一个构造删了,也是可以查到的,因为他找不到别的构造器了,候选构造只有一个
static class Bean1 {
private Bean2 bean2;
private Bean3 bean3;
public Bean1(Bean3 bean3) {
this.bean3 = bean3;
}
public void setBean2(Bean2 bean2) {
this.bean2 = bean2;
}
public void setBean3(Bean3 bean3) {
this.bean3 = bean3;
}
}
但是我们再两个构造器上都加上@Autowired呢?
他会报错构造器已存在
作用2:进行装配(值,引用)
package com.yyl.refresh;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.support.GenericApplicationContext;
import javax.annotation.Resource;
import java.lang.reflect.Constructor;
import java.util.Arrays;
public class BeanPostProcess {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("bean1", Bean1.class);
context.registerBean("bean2", Bean2.class);
context.registerBean("bean3", Bean3.class);
context.refresh();
AutowiredAnnotationBeanPostProcessor beanPostProcessor = new AutowiredAnnotationBeanPostProcessor();
beanPostProcessor.setBeanFactory(context.getDefaultListableBeanFactory());
Bean1 bean1 = new Bean1();
System.out.println("注入之前:"+bean1);
// 处理Bean的属性
beanPostProcessor.postProcessProperties(context.getBeanDefinition("bean1").getPropertyValues(),bean1,"bean1");
System.out.println("注入之后:"+bean1);
}
static class Bean1 {
@Autowired
private Bean2 bean2;
@Autowired
private Bean3 bean3;
// @Value("${JAVA_HOME}")
private Resource resource;
@Override
public String toString() {
return "Bean1{" +
"bean2=" + bean2 +
", bean3=" + bean3 +
", resource=" + resource +
'}';
}
}
static class Bean2 {
}
static class Bean3 {
}
}
CommonAnnotationBeanPostProcessor处理器
识别@Resource、 @PostConstruct、@PreDestroy
package com.yyl.refresh;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
import org.springframework.context.support.GenericApplicationContext;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
public class BeanPostProcessCommon {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("bean1", Bean1.class);
context.registerBean("bean2", Bean2.class);
context.registerBean("commonAnnotationBeanPostProcessor", CommonAnnotationBeanPostProcessor.class);
context.refresh();
System.out.println(context.getBean(Bean1.class).bean2);
// 关闭容器 打印destory1
context.close();
}
static class Bean1 {
private Bean2 bean2;
@Resource
public void setBean2(Bean2 bean2) {
System.out.println("setBean2(Bean2 bean2)");
this.bean2 = bean2;
}
@PostConstruct
public void init1(){
System.out.println("init1");
}
@PreDestroy
public void destory1(){
System.out.println("destory1");
}
}
static class Bean2 {
}
}
7. initMessageSource();
初始化此上下文的消息源,实现国际化
容器中一个名为 messageSource 的 bean,如果没有,则提供空的 MessageSource 实现
执行流程如下图所示:
8. initApplicationEventMulticaster();
为此上下文初始化事件多播器,用来发事件的
- 用来发布事件给监听器
- 可以从容器中找名为 applicationEventMulticaster 的 bean 作为事件广播器,若没有,也会新建默认的事件广播器
- 可以调用 ApplicationContext.publishEvent(事件对象) 来发布事件
执行流程如下:
我们使用如下方式进行发事件:
context.publishEvent(new Object());
context.publishEvent(new ApplicationEvent("source") {
@Override
public Object getSource() {
return super.getSource();
}
});
9. onRefresh();
初始化特定上下文子类中的其他特殊bean
这一步是空实现,留给子类扩展
- SpringBoot 中的子类可以在这里准备 WebServer,即内嵌 web 容器
- 体现的是模板方法设计模式
10. registerListeners();
检查监听器 bean 并注册它们
用来接收事件
一部分监听器是事先编程添加的、另一部分监听器来自容器中的 bean、还有一部分来自于 @EventListener 的解析
实现 ApplicationListener 接口,重写其中 onApplicationEvent(E e) 方法即可
initApplicationEventMulticaster发的事件由事件监听器来接收
执行流如下所示:
registerListeners三种监听器
三种添加方式:
运行结果:
Bean3没有打印出来:缺少必要的后处理器
加一个事件,三个监听器都收到了
在第三步,会加一个监听器
在第八步会初始化监听器
11. finishBeanFactoryInitialization(beanFactory);
实例化所有剩余的(非惰性初始化)单例。
12. finishRefresh();
最后一步:发布相应的事件
最后几步读不动了,改日再读,吐了吐了
边栏推荐
猜你喜欢
随机推荐
信息学奥赛一本通T1452:Keyboarding
el-table实现列筛选功能,控制列的显示和隐藏(实现简单,效果满分)
Multi-Head-Attention原理及代码实现
Getting Started with Chrome Plugin Development
重量级大咖来袭:阿里云生命科学与智能计算峰会精彩内容剧透
Nacos与Eureka的区别
empty() received an invalid combination of arguments - got (tuple, dtype=NoneType, device=NoneType),
第六章:存储系统
【RT_Thread学习笔记】---以太网LAN8720A Lwip ping 通网络
10 common data types in MySQL
七夕和程序员有毛关系?
商业智能BI业务分析思维:供应链分析 – 如何控制牛鞭效应(二)
El - tree to set focus on selected highlight highlighting, the selected node deepen background and change the font color, etc
C语言版本和GCC版本
Postman知识汇总
IEEE RAL投初稿
MySQL的on duplicate key update 的使用
SQL——左连接(Left join)、右连接(Right join)、内连接(Inner join)
jvm 面试题
pyspark---对suuid区间编码(基于曝光数、点击数)