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结构弹计算器Shellcode

    目录 修改记事本PE结构弹计算器Shellcode 0x00 前言 0x01 添加新节 修改节数量 节表位置 添加新节表信息 0x02 添加弹计算器Shellcode 修改代码 0x03 修改入口点 ...

  2. Dubbo的反序列化安全问题-Hessian2

    0 前言 本篇是系列文章的第一篇,主要看看Dubbo使用反序列化协议Hessian2时,存在的安全问题.文章需要RPC.Dubbo.反序列化等前提知识点,推荐先阅读和体验Dubbo以及反序列化漏洞. ...

  3. CSS 脉冲和火箭动画特效

    CSS脉冲和火箭动画特效 <!DOCTYPE html> <html lang="en"> <head> <meta charset=

  4. java.lang.NoSuchFieldError: REFLECTION

    2020-09-14 09:13:21.415 INFO org.apache.cxf.service.factory.ReflectionServiceFactoryBean Line:457 - ...

  5. 求求你们了,别再写满屏的 if/ else 了!

    为什么我们写的代码都是 if-else? 程序员想必都经历过这样的场景:刚开始自己写的代码很简洁,逻辑清晰,函数精简,没有一个 if-else,可随着代码逻辑不断完善和业务的瞬息万变:比如需要对入参进 ...

  6. 如何修改visual-studio的sln文件和project工程名

    关于VS的 .sln 文件和 .suo 文件 *.sln:(Visual Studio.Solution) 通过为环境提供对项目.项目项和解决方案项在磁盘上位置的引用,可将它们组织到解决方案中.比如是 ...

  7. 一行导出所有任意微软SQL server数据脚本-基于Python的微软官方mssql-scripter工具使用全讲解

    文章标题: 一行导出所有任意微软SQL serer数据脚本-基于Python的微软官方mssql-scripter工具使用全讲解 关键字 : mssql-scripter,SQL Server 文章分 ...

  8. MySQL基础语句(修改)

    ①INSERT INSERT INTO students (class_id, name, gender, score) VALUES (2, '大牛', 'M', 80); 向students表插入 ...

  9. [Vue]浅谈Vue3组合式API带来的好处以及选项API的坏处

    前言 如果是经验不够多的同志在学习Vue的时候,在最开始会接触到Vue传统的方式(选项式API),后边会接触到Vue3的新方式 -- 组合式API.相信会有不少同志会陷入迷茫,因为我第一次听到新的名词 ...

  10. python-变量&底层存储原理

    目录 1.变量 1.变量如何使用 2.变量存储的原理 --[ 重点 ] 3.变量存储要遵循印射关系 4.变量三要素 2.常量 3.底层优化 4.垃圾回收机制 1.变量 1.变量如何使用 1.什么是变量 ...