AnnotationConfigApplicationContext(IOC容器)的有参构造方法中,在refresh()里对这些组件进行初始化

BeanPostProcessor

  bean后置处理器,bean创建对象初始化前后进行拦截工作的

BeanFactoryPostProcessor

  refresh()里的invokeBeanFactoryPostProcessors(beanFactory)来初始化BeanFactoryPostProcessor(beanFactory后置处理器,在所有的bean定义信息保存到beanFactory并进行标准初始化之后调用,来定制和修改BeanFactory的内容)

  • String[] postProcessorNames=beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false)
    • 从beanFactory中找到所有类型是BeanFactoryPostProcessor的组件,循环遍历postProcessorNames根据组件优先级加入到不同的集合里(实现了PriorityOrdered的直接在循环中就注册了beanFactoryPostProcessor,其余的之后再一次循环遍历进行注册)
    • 优先级高的集合先执行invokeBeanFactoryPostProcessors(postProcessors,beanFactory),该方法遍历调用postProcessors集合里的对象.postProcessBeanFactory(beanFactory)

BeanDefinitionRegistryPostProcessor

  继承BeanFactoryPostProcessor接口,在invokeBeanFactoryPostProcessors(beanFactory)中,在所有的bean定义信息将要被加载、BeanFactoryPostProcessor初始化之前进行工作

  • String[] postProcessorNames=beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);

    • 从beanFactory中找到所有类型是BeanDefinitionRegistryPostProcessor的组件,也是根据优先级执行invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors,registry),之后依次触发所有的postProcessBeanDefinitionRegistry(registry)可以给容器中再额外添加一些组件

结论

  • invokeBeanFactoryPostProcessors()先从容器中获取到所有的BeanDefinitionRegistryPostProcessor组件(BeanDefinitionRegistryPostProcessor执行过的bean都会保存到一个集合里,执行到BeanFactoryPostProcessor的时候就会进行判断,如果存在说明已经执行过了)
  • 依次触发所有的postProcessBeanDefinitionRegistry()
  • 再来触发BeanFactoryPostProcessor.postProcessBeanFactory()
  • 最后再来从容器中找到BeanFactoryPostProcessor组件,然后依次触发postProcessBeanFactory()
@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor{ @Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// TODO Auto-generated method stub
System.out.println("MyBeanDefinitionRegistryPostProcessor...bean的数量:"+beanFactory.getBeanDefinitionCount());
} //BeanDefinitionRegistry Bean定义信息的保存中心,以后BeanFactory就是按照BeanDefinitionRegistry里面保存的每一个bean定义信息创建bean实例;
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// TODO Auto-generated method stub
System.out.println("postProcessBeanDefinitionRegistry...bean的数量:"+registry.getBeanDefinitionCount());
//RootBeanDefinition beanDefinition = new RootBeanDefinition(Blue.class);
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Blue.class).getBeanDefinition();
registry.registerBeanDefinition("hello", beanDefinition);
} }

ApplicationListener

  监听容器中发布的事件;在refresh()里的registerListeners()里执行getBeanNamesForType(ApplicationListener.class, true, false)获取所有的监听事件,并将它们保存到ApplicationEventMulticaster的listener集合中

 public interface ApplicationListener<E extends ApplicationEvent>  //监听 ApplicationEvent 及其下面的子事件

步骤

  • 实现ApplicationListener接口来监听某个事件(ApplicationEvent及其子类)并加入到容器。只要容器中有相关事件的发布,我们就能监听到这个事件

    • ContextRefreshedEvent:容器刷新完成(所有bean都完全创建)会发布这个事件
    • ContextClosedEvent:关闭容器会发布这个事件
@Component
public class MyApplicationListener implements ApplicationListener<ApplicationEvent> { //当容器中发布此事件以后,方法触发
@Override
public void onApplicationEvent(ApplicationEvent event) {
// TODO Auto-generated method stub
System.out.println("收到事件:"+event);
} }
  • 发布事件
applicationContext.publishEvent(new ApplicationEvent(new String("我发布的时间")) {
});

原理

  • ContextRefreshedEvent

    • 在refresh()里的finishRefresh()中执行了publishEvent(new ContextRefreshedEvent(this));在容器刷新完成的最后一步方法里发布ContextRefreshedEvent事件
  • ContextClosedEvent
    • 执行applicationContext.close()关闭容器的doClose()中执行了publishEvent(new ContextClosedEvent(this))

  所有的事件发布都调用了publishEvent(),而在这方法里主要做了这几件事:

  • 获取事件的多播器(派发器):getApplicationEventMulticaster(),并通过multicastEvent()派发事件,在该方法中获取到所有的ApplicationListener进行遍历(如果有Executor,可以支持使用Executor进行异步派发;否则,同步的方式直接执行invokeListener(listener, event)),拿到listener回调onApplicationEvent()

@EventListener

  使用EventListenerMethodProcessor处理器解析方法上的@EventListener,它实现SmartInitializingSingleton的afterSingletonsInstantiated();

  在refresh()里的finishBeanFactoryInitialization(beanFactory)里创建完所有单例bean后,会获取所有的bean判断是否是SmartInitializingSingleton类型的,如果是就调用afterSingletonsInstantiated()

@EventListener(classes={ApplicationEvent.class})
public void listen(ApplicationEvent event){
System.out.println("监听到的事件:"+event);
}

事件的多播器

  在refresh()里的initApplicationEventMulticaster()中初始化ApplicationEventMulticaster,先去容器中找有没有id=“applicationEventMulticaster”的组件,如果没有this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);并通过beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster)注册到容器中去,在其他组件要派发事件就可以自动注入这个applicationEventMulticaster

spring注解-扩展原理的更多相关文章

  1. 重新学习Spring注解——扩展原理

    39.扩展原理-BeanFactoryPostProcessor 40.扩展原理-BeanDefinitionRegistryPostProcessor 41.扩展原理-ApplicationList ...

  2. Spring注解实现原理

    ​[Spring如何使用注解机制完成自动装配] Java实例构造时会调用默认父类无参构造方法,Spring正是利用了这一点,让"操作元素的代码"得以执行.   [两种处理策略] ( ...

  3. Spring注解驱动开发(五)-----扩展原理

    扩展原理 1.BeanPostProcessor-----bean后置处理器,bean创建对象初始化前后进行拦截工作的 2.BeanFactoryPostProcessor-----beanFacto ...

  4. 【spring 注解驱动开发】扩展原理

    尚学堂spring 注解驱动开发学习笔记之 - 扩展原理 扩展原理 1.扩展原理-BeanFactoryPostProcessor BeanFactoryPostProcessor * 扩展原理: * ...

  5. Spring注解驱动开发之扩展原理

    前言:现今SpringBoot.SpringCloud技术非常火热,作为Spring之上的框架,他们大量使用到了Spring的一些底层注解.原理,比如@Conditional.@Import.@Ena ...

  6. Spring 注解原理(三)@Qualifier @Value

    Spring 注解原理(三)@Qualifier @Value Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) 一.Aut ...

  7. spring Mvc 执行原理 及 xml注解配置说明 (六)

    Spring MVC 执行原理 在 Spring Mvc 访问过程里,每个请求都首先经过 许多的过滤器,经 DispatcherServlet 处理; 一个Spring MVC工程里,可以配置多个的 ...

  8. 这一次搞懂Spring自定义标签以及注解解析原理

    前言 在上一篇文章中分析了Spring是如何解析默认标签的,并封装为BeanDefinition注册到缓存中,这一篇就来看看对于像context这种自定义标签是如何解析的.同时我们常用的注解如:@Se ...

  9. [转]Spring注解原理的详细剖析与实现

    原文地址:http://freewxy.iteye.com/blog/1149128/ 本文主要分为三部分: 一.注解的基本概念和原理及其简单实用 二.Spring中如何使用注解 三.编码剖析spri ...

随机推荐

  1. PE节表详细分析

    目录 PE节表详细分析 0x00 前言 0x01 PE节表分析 节表结构 节表数量 节表名字 节表大小 节位置 节表属性 0x02 代码编写 PE节表详细分析 0x00 前言 上一篇文章我们学习了PE ...

  2. DockerFile-构建容器的基石

    DockerFile 非常的关键,它不同于 docker commit 的手动命令方式来进行镜像的构建和修改,类似 docker commit 的交互被称为命令式交互.命令式交互是运维一直绕不开的一种 ...

  3. [cf611H]New Year and Forgotten Tree

    首先,来构造这棵树的形态 称位数相同的点为一类点,从每一类点中任选一个点,具有以下性质: 1.每一类中选出的点的导出子图连通(是一颗树) 2.每一条边必然有一个端点属于某一类中选出的点 (关于&quo ...

  4. [bzoj1863]皇帝的烦恼

    二分枚举答案,假设是ans,考虑判定答案从前往后计算,算出每一个将军与第一个将军最少和最多有多少个相同的奖牌,贪心转移即可 1 #include<bits/stdc++.h> 2 usin ...

  5. C语言下的Led灯

    1. 设计思想 1.1 设置处理器模式 设置sp啥的汇编要先进入SVC模式,超级管理员特权模式,这样就可以访问所有寄存器了,需要用到cpsr寄存器 0到4位要设置svc模式10011 = 0x13, ...

  6. vue-通过name进行数据过滤

    <template> <div> <h3>搜索列表</h3> <input type="text" placeholder=& ...

  7. k8s-数据持久化存储卷,nfs,pv/pvc

    目录 数据持久化-储存卷 官方文档 存储卷类型 1.emptyDir 2.hostpath 3.pv/pvc(推荐使用) nfs官方文档 安装测试nfs pv/pvc管理nfs 官方文档 pv/pvc ...

  8. P7045 「MCOI-03」金牌

    考虑维护一个队列. 先插入\(a_1 = 0\) 依次往后考虑,如果和队列里相斥,则我们把队列一个和他捆绑起来. 如果队列空,则加入该颜色. 最后考虑往队列里插入改颜色. 总共为\(2 * (n - ...

  9. Codeforces 1270E - Divide Points(构造+奇偶性)

    Codeforces 题目传送门 & 洛谷题目传送门 显然,直接暴力枚举是不可能的. 考虑将点按横纵坐标奇偶性分组,记 \(S_{i,j}=\{t|x_t\equiv i\pmod{2},y_ ...

  10. R之dplyr::select/mutate函数扩展

    select函数 dplyr包select函数用的很多,不过我们一般也是通过正反选列名或数字来选择列. 常见用法如: select(iris,c(1,3)) select(iris,1,3) #同上 ...