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

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

组件注册相关

@Configuration

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

@Bean

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

基本使用:

@Configuration
public 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<Color> {
        // 返回要注册的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

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

注:

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

@ComponentScan

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

基本使用:

@Configuration
@ComponentScan
public 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")// 单例
    @Bean
    public Person person() {
        return new Person("11", "张三");
    }
    
  2. 指定Bean为多例

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

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

@Lazy

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

基本使用:

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

@Conditional(重要)

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

public @interface Conditional {
   Class<? extends Condition>[] 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:给容器中导入一个组件

基本使用:

// 定义一个Color
public 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注解配置初始化和销毁方法

    @Configuration
    public 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注入该组件

    @Configuration
    public 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. 向容器中注册该组件

    @Configuration
    public 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 <i>before</i> any bean
     * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
     * or a custom init-method).
     */
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
       return bean;
    }
    
  2. postProcessAfterInitialization:类似的,该方法会在我们实现 InitializingBean 的初始化方法 和 @Bean中指定的 init-method 方法调用之后调用

    @Nullable
    default 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 方法:

    @Override
    public 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返回。

@Override
public 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容器:

@Component
public 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() {}
    }
    

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

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

自动装配相关

@Autowired

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

基本使用:

@Service
public class TestService {

    @Autowired
    private TestDao testDao;
	...
}

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

@Qualifier

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

基本使用:

@Service
public 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. 导包

    <dependency>
        <groupId>javax.inject</groupId>
        <artifactId>javax.inject</artifactId>
        <version>1</version>
    </dependency>
    
  2. 使用:

    @Inject
    private TestDao testDao;
    

和@Autowired的区别:

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

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

标注在方法上

基本使用:

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

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

标注在构造器上

基本使用:

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

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

标注在方法参数上

基本使用

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

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

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

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

xxxAware注入

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

使用实例:

@Component
public 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<Object>) () -> {
         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,并执行他们的方法。

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

BeanDefinitionRegistryPostProcessor

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

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

@Component
public 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数量:9
postProcessBeanFactory:当前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 及其下面子事件
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { ... }

步骤:

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

    @Component
    public class TestApplicationListener implements ApplicationListener<ApplicationEvent> {
        @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

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

基本使用:

@Repository
public 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

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

基本使用:

@Repository
public 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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值