博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring组件注册、Bean生命周期、自动装配相关知识
阅读量:3914 次
发布时间:2019-05-23

本文共 23097 字,大约阅读时间需要 76 分钟。

Spring组件注册、Bean生命周期、自动装配相关知识

组件注册相关

文章目录

@Configuration

作用:表明该类是一个配置类,内部其实是一个@Component

@Bean

作用:向IOC容器中注册一个Bean,类型为返回值的类型,id默认是用方法名作为id

基本使用:

@Configurationpublic class TestConfig {
@Bean public Person person() {
return new Person("11", "张三"); }}

也可以指定bean的id:

@Bean("person")public Person person() {
return new Person("11", "张三");}

使用FactoryBean注入

作用:为容器中注册Bean

基本使用:

  1. 定义FactoryBean的实现类

    // 泛型指定为要注册Bean的类型public class ColorFactoryBean implements FactoryBean
    {
    // 返回要注册的Bean @Override public Color getObject() throws Exception {
    return new Color(); } // 返回Bean类型 @Override public Class
    getObjectType() {
    return Color.class; } // 指定是否单例 @Override public boolean isSingleton() {
    return true; }}
  2. 在配置类中注册FactoryBean

    @Configurationpublic class TestConfig04 {
    // 注册FactoryBean @Bean public ColorFactoryBean colorFactoryBean() {
    return new ColorFactoryBean(); }}

注:

  1. 默认获取到的是工厂Bean调用 getObject() 方法获取的对象
  2. 要获取工厂Bean本身,我们可以在id前加一个&,如 &color

@ComponentScan

作用:扫描指定目录下的组件,若不指定目录,则扫描当前路径下的组件。

基本使用:

@Configuration@ComponentScanpublic class TestConfig {
@Bean public Person person() {
return new Person("11", "张三"); }}

还可以通过value或basePackages属性指定要扫描的包includeFilters或excludeFilters指定要扫描或者要排除的类型,示例如下:

@Configuration@ComponentScan(basePackages = "com.zsp", includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)})public class TestConfig {
@Bean public Person person() {
return new Person("11", "张三"); }}

@Filter

@ComponentScan内部的一个注解,用来定义过滤规则,如按照注解过滤(如上例),按照类型过滤等。

@ComponentScans

作用:内部指定多个@Componentscan

基本使用:

@Configuration@ComponentScans(value = {
@ComponentScan(basePackages = "com.zsp", includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class) })})public class TestConfig {
...}

@Scope

作用:指定Bean的Scope(作用域)

注:Bean的四种作用域:Singleton、Prototype、Request、Session

基本使用:

  1. 指定Bean为单例

    @Scope("singleton")// 单例@Beanpublic Person person() {
    return new Person("11", "张三");}
  2. 指定Bean为多例

    @Scope("prototype")// 多实例@Beanpublic Person person() {
    return new Person("11", "张三");}

注:单例情况下,容器启动时就会调用方法创建对象到IOC容器中,以后每次获取就是直接从容器中(一级缓存)中拿;多实例状态下,IOC容器启动不会调用方法创建对象,而是获取时才调用。

@Lazy

作用:将Bean设置为懒加载(获取时才创建对象)

基本使用:

@Lazy // 懒加载@Beanpublic Person person() {
return new Person("11", "张三");}

@Conditional(重要)

作用:按照一定条件判断,满足条件给容器中注册bean,一起看一下这个注解:

public @interface Conditional {
Class
[] value();}

@Conditional内部包含一个Condition数组,Condition是一个接口,我们可以通过写这个接口的实现类来实现对这个注解的配置。

方法上:

如:

@Conditional(value = {
UserCondition.class})@Bean("zhangsan")public User zhangsan() {
return new User(15, "张三");}public class UserCondition implements Condition {
@Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 1,获取Bean工厂 ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); // 2,获取类加载器 ClassLoader classLoader = context.getClassLoader(); // 3,获取当前环境信息 Environment environment = context.getEnvironment(); // 4,获取Bean定义信息 BeanDefinitionRegistry registry = context.getRegistry(); return false; }}

Condition给我们提供的方法参数可以用来获取BeanFactory,环境等信息。

示例:若系统是Windows则注册bill组件,如系统是linux则注册linus组件:

首先实现Condition接口

// 实现Condition接口public class LinusCondition implements Condition {
@Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment(); String property = environment.getProperty("os.name");//获取系统名称 if (property != null && property.contains("linux")) {
return true; } return false; }}

接着环境变量和配置注解:

环境变量:-Dos.name=linux

注解配置:

@Conditional(value = {
BillCondition.class})@Bean("bill")public User bill() {
return new User(88, "Bill Gates");}@Conditional(value = {
LinusCondition.class})@Bean("linus")public User linus() {
return new User(88, "linus");}

类上:

标注在类上:满足当前条件,这个类中配置的所有的bean才能生效(统一设置)。

@Import

作用:快速给容器中导入一个组件(id默认是组件的全类名

补充:

  1. 包扫描+组件标注注解注入:@Controller、@Service、@Repository、@Component
  2. @Bean:导入组件
  3. @Import:给容器中导入一个组件

基本使用:

// 定义一个Colorpublic class Color {
...}@Configuration@Import(value = {
Color.class}) // 导入Color组件,id默认全类名,可以传入数组public class TestConfig03 {
...}

@Import的第二种用法——ImportSelector:

作用:返回需要导入的组件的全类名数组

使用步骤:

  1. 自定义类实现ImportSeletor接口,并重写selectImports()方法

    public class TestImportSeletor implements ImportSelector {
    /** * * @param importingClassMetadata 获取被@Import标注的类的信息 * @return 返回要注入组件的全类名数组 */ @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) {
    return new String[]{
    "com.zsp.domain.Color"}; }}
  2. 配置类加上该注解

    @Configuration@Import(value = {
    TestImportSeletor.class})public class TestConfig03 {
    ... }

注意:该方法导入的bean id也是bean的全类名。

@Import的第三种用法——ImportBeanDefinitionRegistrar

作用:给容器中注册组件

基本使用:

  1. 定义类实现 ImportBeanDefinitionRegistrar 接口并重写 registerBeanDefinitions() 方法

    public class TestImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    boolean containsColor = registry.containsBeanDefinition("com.zsp.domain.Color"); if (containsColor) {
    // 指定Bean定义信息 注意这里需要传入类型 RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Green.class); registry.registerBeanDefinition("green", rootBeanDefinition); } }}

    2,注解配置该实现类

    @Configuration@Import(value = {
    Color.class, TestImportBeanDefinitionRegistrar.class})public class TestConfig03 {
    ... }

Bean生命周期相关

@Bean指定初始化和销毁方法

基本使用:

  1. Bean中书写初始化和销毁方法

    public class Car {
    public Car() {
    System.out.println("创建..."); } // 初始化方法 public void init() {
    System.out.println("init..."); } // 销毁方法 public void destroy() {
    System.out.println("destroy..."); }}
  2. @Bean注解配置初始化和销毁方法

    @Configurationpublic class TestConfig05 {
    // 配置初始化和销毁方法 @Bean(name = "car", initMethod = "init", destroyMethod = "destroy") public Car car() {
    return new Car(); }}

备注:

  • 关于初始化:单实例下,在容器启动时就会创建对象接着调用初始化方法,而多实例是在每次获取的时候创建对象接着调用初始化方法
  • 关于销毁:单实例下,容器关闭时调用销毁方法,而多实例下容器不会管理这个bean,也不会调用销毁方法

通过实现 InitializingBean 和DisposableBean 定义初始化和销毁方法

基本使用:

  1. 分别实现两接口的 afterPropertiesSet()destroy() 方法

    // 实现两接口并实现初始化和销毁方法public class Cat implements InitializingBean, DisposableBean {
    public Cat() {
    System.out.println("Cat创建..."); } @Override public void destroy() throws Exception {
    System.out.println("销毁..."); } @Override public void afterPropertiesSet() throws Exception {
    System.out.println("初始化..."); }}
  2. 使用@Bean注入该组件

    @Configurationpublic class TestConfig06 {
    @Bean(name = "cat") // 注册 public Cat cat() {
    return new Cat(); }}

JSR 250注解实现:@PostConstant(创建之后) @PreDestroy(销毁之前)

基本使用:

  1. 组件类定义初始化和销毁方法并加上两注解

    public class Dog {
    public Dog() {
    System.out.println("创建..."); } // 实例化之后调用 @PostConstruct public void init() {
    System.out.println("init..."); } // 销毁之前调用 @PreDestroy public void destroy() {
    System.out.println("destroy..."); }}
  2. 向容器中注册该组件

    @Configurationpublic class TestConfig07 {
    @Bean(name = "dog") // 注册 public Dog dog() {
    return new Dog(); }}

BeanPostProcessor接口——Bean后置处理器

作用:在bean初始化前后进行一些处理工作

BeanPostProcessor 接口内部提供两个方法:

  1. postProcessBeforeInitialization:根据Spring官方的介绍,该方法将会在我们实现 InitializingBean 的初始化方法 和 @Bean中指定的 init-method 方法调用之前调用

    /** * Apply this {@code BeanPostProcessor} to the given new bean instance before any bean * initialization callbacks (like InitializingBean's {@code afterPropertiesSet} * or a custom init-method). */@Nullabledefault Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    return bean;}
  2. postProcessAfterInitialization:类似的,该方法会在我们实现 InitializingBean 的初始化方法 和 @Bean中指定的 init-method 方法调用之后调用

    @Nullabledefault Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    return bean;}

基本使用:

  1. 定义自定义后置处理器(实现 BeanPostProcessor)并将其注册到容器中,之后重写before和after两个方法:

    @Component// 注册public class AnimalBeanPostProcessor implements BeanPostProcessor {
    @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("postProcessBeforeInitialization: " + beanName + "...."); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("postProcessAfterInitialization: " + beanName + "...."); return bean; }}
  2. 定义Animal类用来测试

    public class Animal implements InitializingBean, DisposableBean {
    public Animal() {
    System.out.println("Animal construct ..."); } @Override public void destroy() throws Exception {
    System.out.println("DisposableBean destroy ..."); } @Override public void afterPropertiesSet() throws Exception {
    System.out.println("InitializingBean init ..."); } public void initMethod() {
    System.out.println("init-method ..."); } public void destroyMethod() {
    System.out.println("destroy-method ..."); }}
  3. 向容器中注册Animal,并定义初始化方法

    @Configuration@ComponentScan(basePackages = "com.zsp")public class TestConfig08 {
    @Bean(name = "animal", initMethod = "initMethod", destroyMethod = "destroyMethod") public Animal animal() {
    return new Animal(); }}
  4. 测试结果

    Animal construct ...  // 构造方法postProcessBeforeInitialization: animal.... // before处理InitializingBean init ...   // InitializingBean的afterPropertiesSet方法init-method ... // @Bean中配置的初始化方法init()postProcessAfterInitialization: animal.... //after处理

BeanPostProcessor 工作原理

在IOC的初始化过程中,由populateBean(beanName) 对Bean进行属性赋值后,initializeBean()方法进行以下操作:

  • applyBeanPostProcessorsBeforeInitialiaztion(wrappedBean, beanName):首先由该方法获取所有的BeanPostProcessor,并挨个执行(遍历),一旦有一个返回null就会跳出循环,不会执行后续的processor brfore 方法:

    @Overridepublic Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)      throws BeansException {
    Object result = existingBean; // getBeanPostProcessors() 获取所有的Bean processors // 遍历执行所有的processor for (BeanPostProcessor processor : getBeanPostProcessors()) {
    Object current = processor.postProcessBeforeInitialization(result, beanName); if (current == null) {
    return result; // 如果一个为null,则接下来的全部返回 } result = current; } return result;}
  • invokeInitMethods(beanName, wrappedBean, mbd):执行我们自定义的初始化方法(@Bean中定义的init-method和实现的afterPropertiesSet() 方法)

  • applyBeanPostProcessorsAfterInitialization(existingBean, beanName):同样的,在初始化方法执行完成之后执行,同样是获取所有的processor,遇null返回。

@Overridepublic Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)      throws BeansException {
Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName); if (current == null) {
return result; } result = current; } return result;}

Spring 底层对 BeanPostProcessor 的使用

如 ApplicationContextAwareProcessor 就是用来处理 ApplicationContextAware 的初始化方法。例如,我们可以通过实现ApplicationContextAware来完成 ApplicationContextAwareProcessor 对 ApplicationContextAware的处理,并为我们在组件中实例化一个IOC容器:

@Componentpublic class Fish implements ApplicationContextAware {
public ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext; }}

又比如 AutowiredAnnotationBeanPostProcessor,帮助我们完成@Autowired标注属性的自动注入工作。

属性赋值相关

@Value

作用:属性赋值

用法:

  1. 写基本数值:

    @Value("张三")private String name;
  2. 写SpEL表达式

    @Value("#{1 + 1}")private Integer id;
  3. ${} 取出配置文件中的值:该方式在介绍下一个注解时介绍

备注:@Value同样可以用在方法参数上

@PropertySource

作用:类似xml配置方式的< context:property-placeholder >标签,用来定义配置文件的位置并导入配置文件

用法:

  1. 定义配置文件 teacher.properties,内容如下:

    teacher.name=张三teacher.id=1
  2. 在配置类中使用 @PropertySource 注入:

    @Configuration@ComponentScan("com.zsp.domain")@PropertySource("classpath:teacher.properties")public class TestConfig09 {
    @Bean public Teacher teacher() {
    return new Teacher(); }}
  3. 实体类中:

    public class Teacher {
    @Value("${teacher.id}") private Integer id; @Value("${teacher.name}") private String name; public Teacher() {
    }}

同样的,我们也可以通过环境变量来获取这些配置文件中的属性值:

@Testpublic void test2() {
ApplicationContext ioc = new AnnotationConfigApplicationContext(TestConfig09.class); // 通过ioc容器获取环境变量 Environment environment = ioc.getEnvironment(); String property = environment.getProperty("teacher.name"); System.out.println(property);}

自动装配相关

@Autowired

作用:自动注入(默认是优先按照类型去容器中找)

基本使用:

@Servicepublic class TestService {
@Autowired private TestDao testDao; ...}

备注:@Autowired是有限按照类型去容器中找对应的组件,如果找到多个类型相同的组件,再将属性名称按照组件的id去容器中找

@Qualifier

作用:指定要装配的组件id,和@Autowired配合使用

基本使用:

@Servicepublic class TestService {
@Qualifier("testDao") // 指定组件id @Autowired private TestDao testDao; ...}

@Primary

作用:让Spring进行自动装配时,默认使用首选(被该注解标注)的Bean。

@Resource——JSR250规范

作用:属性注入

基本使用:

@Resource(name = "testDao")private TestDao testDao;

和@Autowired的区别

  • 可以和@Autowired一样实现自动装配功能
  • 默认按组件名称进行装配
  • 不支持@Primary指定优先级
  • 没有@Autowired(required=false)这样的功能

@Inject——JSR330

作用:属性注入

基本使用:

  1. 导包

    javax.inject
    javax.inject
    1
  2. 使用:

    @Injectprivate TestDao testDao;

和@Autowired的区别:

  • 一样能实现自动注入
  • 支持@Primary
  • 没有@Autowired(required=false)这样的功能

方法、构造器位置的自动装配

标注在方法上

基本使用:

@Autowiredpublic void setTestDao(TestDao testDao) {
this.testDao = testDao;}

备注:标注在方法上时,方法使用的参数将会从ioc容器中获取

标注在构造器上

基本使用:

@Autowiredpublic TestService(TestDao testDao) {
this.testDao = testDao;}

备注:标注在构造器上时,方法参数也是从容器中获取。如果组件只有一个有参构造器,那么有参构造器的@Autowired可以省略,参数位置的组件还是可以从容器中获取

标注在方法参数上

基本使用

public void setTestDao(@Autowired TestDao testDao) {
this.testDao = testDao;}

@Bean标注的方法创建对象时,方法参数的值从容器中获取

即以下两种方式用不用@Autowired都一样,没有区别:

@Beanpublic Teacher teacher(@Autowired Classes classes) {
return new Teacher(classes);}// 不加 @Autowired@Beanpublic Teacher teacher(Classes classes) {
return new Teacher(classes);}

xxxAware注入

自定义组件中想要使用Spring容器中的一些组件,如:ApplicationContext、BeanFactory等,只需要自定义组件实现xxxAware,在创建对象时,会调用接口规定的方法注入相关组件。

使用实例:

@Componentpublic class Watch implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware {
// 获取Bean名称 @Override public void setBeanName(String name) {
System.out.println("当前bean的name为:" + name); } // 获取ioc容器 @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("当前ioc容器:" + applicationContext); } //获取String值解析器 @Override public void setEmbeddedValueResolver(StringValueResolver resolver) {
String s = resolver.resolveStringValue("老师名字叫${teacher.name}, 今年#{15+20}岁"); System.out.println(s); }}

原理:

每一个xxxAware都有一个对应的xxxAwareProcessor用来处理,如ApplicationContextAware就有ApplicationContextAwareProcessor用来处理,前面对BeanPostProcessor的介绍我们知道:BeanPostProcessor的子类可以通过实现父类的postProcessBeforeInitialization()方法进行一些操作,这些AwareProcessor正是通过这个方法完成注入操作,下面是ApplicationContextAwareProcessor的源码:

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware || bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware || bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware || bean instanceof ApplicationStartupAware)) {
return bean; } AccessControlContext acc = null; if (System.getSecurityManager() != null) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext(); } if (acc != null) {
AccessController.doPrivileged((PrivilegedAction) () -> {
invokeAwareInterfaces(bean); return null; }, acc); } else {
invokeAwareInterfaces(bean); // 调用Aware方法 } return bean;}

@Profile

作用:Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能,指定组件在哪个环境的情况下才能被注册到容器中,不指定,则任何环境下都能注册这个组件

备注:加了环境标识的bean,只有这个环境被激活时才能注册到容器中默认是default环境)。

如,不同环境加载不同数据源(生产、开发、测试):

// 使用命令行动态参数,在虚拟机参数位置加(也可以在ApplicationContext中设置):-Dspring.profiles.active=test// 注册组件@Profile("test")@Bean("dataSource")public DataSource dataSourceTest() {
...}@Profile("dev")@Bean("dataSource")public DataSource dataSourceDev() {
...}@Profile("pro")@Bean("dataSource")public DataSource dataSourceProv() {
...}

需要注意以下两点:

  1. 写在类上时,只有是指定环境的时候,整个配置类里面的所有配置才能开始生效
  2. 加了环境标识的bean,只有这个环境被激活时才能注册到容器中默认是default环境
  3. 没有标注环境表示的bean,任何环境下都能注册到容器中

扩展

BeanFactoryPostProcessor

BeanPostProcessor:前面我们介绍了BeanPostProcessor,它是一个bean的后置处理器,在bean创建对象的初始化前后进行拦截工作。

BeanFactoryPostProcessor:BeanFactory的后置处理器,在BeanFactory标准初始化之后调用,所有的Bean定义已经保存加载到BeanFactory中,但是还未执行Bean的实例化过程的时候执行。

和BeanPostProcessor一样,在refresh()中的invokeBeanFactoryPostProcessors(beanFactory)中,首先找到所有的BeanFactoryPostProcessor,并执行他们的方法。

@Componentpublic class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println(beanFactory); }}

BeanDefinitionRegistryPostProcessor

它是BeanFactoryPostProcessor的子接口,在所有Bean定义信息将要被加载,但Bean实例还未创建的时候执行。

作用:优先于BeanFactoryPostProcessor执行,利用BeanDefinitionRegistryPostProcessor可以给容器中再额外添加一些组件,实例如下:

@Componentpublic class TestBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("postProcessBeanDefinitionRegistry:当前bean数量:" + registry.getBeanDefinitionNames().length); // 添加组件 registry.registerBeanDefinition("color", new RootBeanDefinition(Color.class)); } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("postProcessBeanFactory:当前bean数量:" + beanFactory.getBeanDefinitionNames().length); }}// 打印结果postProcessBeanDefinitionRegistry:当前bean数量:9postProcessBeanFactory:当前bean数量:10

原理:在refresh()方法中,调用 invokeBeanFactoryPostProcessors 方法,首先从容器中获取到所有的 BeanDefinitionRegistryPostProcessor 组件再来依次触发所有的 postProcessBeanDefinitionRegistry() 方法,接着再来触发它们的 postProcessBeanFactory()方法。执行完这些之后,再从容器中找到BeanFactoryPostProcessor组件,然后依次触发postProcessBeanFactory()

源码:

while (reiterate) {
reiterate = false; postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); reiterate = true; } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); // 首先调用 invokeBeanDefinitionRegistryPostProcessors invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup()); currentRegistryProcessors.clear();}// Now, invoke the postProcessBeanFactory callback of all processors handled so far.invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);

BeanDefinitionRegistry

介绍:Bean定义信息的保存中心,以后BeanFactory就是按照BeanDefinitionRegistry里面保存的每一个bean定义信息创建Bean实例。

ApplicationListener

作用:监听容器中发布的事件,事件驱动模型开发。

// 监听ApplicationEvent 及其下面子事件@FunctionalInterfacepublic interface ApplicationListener
extends EventListener {
... }

步骤:

  1. 写一个监听器来监听某个事件,并注册到容器

    @Componentpublic class TestApplicationListener implements ApplicationListener
    {
    @Override public void onApplicationEvent(ApplicationEvent event) {
    System.out.println(event); }}
  2. 只要容器中有相关事件的发布,我们就能监听到这个事件。

原理:

事件发布流程

  • 容器创建对象:refresh()
  • finishRefresh()
  • publishEvent(new ContextRefershedEvent(this))
    • 获取事件的多播器(派发器):getApplicationEventMulticaster()
    • multicastEvent派发事件
    • 获取到所有的ApplicationListener
      • 循环
        • 如果有Executor,可以支持使用Executor异步派发
        • 否则直接执行listener方法:invokeListener()

事件多播器(派发器)

  1. 容器创建对象:refresh()
  2. initApplicationEventMulticaster():初始化ApplicationEventMulticaster
    1. 先去容器中找有没有 id="applicationEventMulticaster"的组件
    2. 如果没有则new SimpleApplicationEventMulticaster(beanFactory),并且加入到容器。我们要在其他组件派发事件,就自动注入这个applicationEventMulticaster;

容器中有哪些监听器

  1. 容器创建对象:refresh()

  2. registerListeners()

    1. 从容器中拿到所有的监听器,把他们注册到applicationEventMulticaster中

      // 获取所有监听器String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);// 添加到派发器中for (String listenerBeanName : listenerBeanNames) {
      getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);}

@EventListener

作用:标注的方法在监听的事件发布时执行

基本使用:

@Repositorypublic class TestDao {
@EventListener(classes = ApplicationEvent.class) public void listen() {
System.out.println("监听...."); }}

原理:

  1. 使用EventListenerMethodProcessor处理器来解析方法上的@EventListener
  2. EventListenerMethodProcessor实现了SmartInitializingSingleton接口
  3. SmartInitializingSingleton原理:
    1. ioc容器创建对象并refresh()
    2. finishBeanFactoryInitialization(beanFactory);初始化剩下的单实例bean
      1. 先创建所有的单实例bean
      2. 获取所有创建好的单实例bean,判断是否SmartInitializingSingleton类型的,如果是就调用afterSingletonsInstantiated

附视频学习链接:https://www.bilibili.com/video/BV1oW41167AV

r;

容器中有哪些监听器

  1. 容器创建对象:refresh()

  2. registerListeners()

    1. 从容器中拿到所有的监听器,把他们注册到applicationEventMulticaster中

      // 获取所有监听器String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);// 添加到派发器中for (String listenerBeanName : listenerBeanNames) {
      getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);}

@EventListener

作用:标注的方法在监听的事件发布时执行

基本使用:

@Repositorypublic class TestDao {
@EventListener(classes = ApplicationEvent.class) public void listen() {
System.out.println("监听...."); }}

原理:

  1. 使用EventListenerMethodProcessor处理器来解析方法上的@EventListener
  2. EventListenerMethodProcessor实现了SmartInitializingSingleton接口
  3. SmartInitializingSingleton原理:
    1. ioc容器创建对象并refresh()
    2. finishBeanFactoryInitialization(beanFactory);初始化剩下的单实例bean
      1. 先创建所有的单实例bean
      2. 获取所有创建好的单实例bean,判断是否SmartInitializingSingleton类型的,如果是就调用afterSingletonsInstantiated

附视频学习链接:https://www.bilibili.com/video/BV1oW41167AV

转载地址:http://wkprn.baihongyu.com/

你可能感兴趣的文章
一位资深程序员大牛给予Java初学者的学习路线建议
查看>>
Java后端2017书单推荐
查看>>
Java的内存回收机制
查看>>
2年Java开发工作经验面试总结
查看>>
最全面的Java多线程用法解析
查看>>
Java ClassLoader 原理详细分析
查看>>
Java中创建对象的5种方式
查看>>
Java并发控制机制详解
查看>>
Java Executor 框架学习总结
查看>>
15个顶级Java多线程面试题及答案
查看>>
成为优秀Java程序员的10大技巧
查看>>
一位10年Java工作经验的架构师聊Java和工作经验
查看>>
Java架构师学习路线
查看>>
号称精通Java的你,是否真的名副其实
查看>>
你可以把编程当做一项托付终身的职业
查看>>
细思极恐——你真的会写Java吗?
查看>>
Java并发面试,幸亏有点道行,不然又被忽悠了
查看>>
Java基础面试题收集整理
查看>>
SpringBoot基础篇Bean之条件注入@Condition使用姿势
查看>>
让你秒懂线程和线程安全,只需5步!
查看>>