当前位置:网站首页>解读 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();
最后一步:发布相应的事件
最后几步读不动了,改日再读,吐了吐了
边栏推荐
猜你喜欢
el-table gets the data attribute of a row in the read data table
empty() received an invalid combination of arguments - got (tuple, dtype=NoneType, device=NoneType),
torch.nn.modules.activation.ReLU is not a Module subclass
prometheus 监控mysql数据库
用代码构建UI界面
MySQL的DATE_FORMAT()函数将Date转为字符串
postman配置中文
pyspark df 二次排序
MySQL 流程控制
Cesium loads offline maps and offline terrain
随机推荐
qt学习之旅--MinGW编译FFmpeg(32bit)
Nacos下载与安装
spark中的bykey
MYSQL存储过程注释详解
Cesium loads offline maps and offline terrain
Umi 4 快速搭建项目
MySQL - 触发器
AlexNet网络详解及复现
uniapp 请求接口封装
prometheus 监控mysql数据库
Cesium加载离线地图和离线地形
pyspark --- count the mode of multiple columns and return it at once
Example of embedding code for continuous features
第一章:ARM公司Cortex-M 系列处理器介绍,第二章:嵌入式软件开发介绍和第三章:Cortex-M3和Cortex-M4处理器的一般介绍
信息学奥赛一本通T1447:靶形数独
el-table获取读取数据表中某一行的数据属性
解决plt.imshow()不显示图片cv2.imshw()不显示图片
C语言版本和GCC版本
keepalived安装部署
编程语言有什么