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
基本使用:
-
定义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; } }
-
在配置类中注册FactoryBean
@Configuration public class TestConfig04 { // 注册FactoryBean @Bean public ColorFactoryBean colorFactoryBean() { return new ColorFactoryBean(); } }
注:
- 默认获取到的是工厂Bean调用 getObject() 方法获取的对象
- 要获取工厂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
基本使用:
-
指定Bean为单例
@Scope("singleton")// 单例 @Bean public Person person() { return new Person("11", "张三"); }
-
指定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默认是组件的全类名)
补充:
- 包扫描+组件标注注解注入:@Controller、@Service、@Repository、@Component
- @Bean:导入组件
- @Import:给容器中导入一个组件
基本使用:
// 定义一个Color
public class Color {
...
}
@Configuration
@Import(value = {Color.class}) // 导入Color组件,id默认全类名,可以传入数组
public class TestConfig03 {...}
@Import的第二种用法——ImportSelector:
作用:返回需要导入的组件的全类名数组
使用步骤:
-
自定义类实现ImportSeletor接口,并重写selectImports()方法
public class TestImportSeletor implements ImportSelector { /** * * @param importingClassMetadata 获取被@Import标注的类的信息 * @return 返回要注入组件的全类名数组 */ @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { return new String[]{"com.zsp.domain.Color"}; } }
-
配置类加上该注解
@Configuration @Import(value = {TestImportSeletor.class}) public class TestConfig03 { ... }
注意:该方法导入的bean id也是bean的全类名。
@Import的第三种用法——ImportBeanDefinitionRegistrar
作用:给容器中注册组件
基本使用:
-
定义类实现 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指定初始化和销毁方法
基本使用:
-
Bean中书写初始化和销毁方法
public class Car { public Car() { System.out.println("创建..."); } // 初始化方法 public void init() { System.out.println("init..."); } // 销毁方法 public void destroy() { System.out.println("destroy..."); } }
-
@Bean注解配置初始化和销毁方法
@Configuration public class TestConfig05 { // 配置初始化和销毁方法 @Bean(name = "car", initMethod = "init", destroyMethod = "destroy") public Car car() { return new Car(); } }
备注:
- 关于初始化:单实例下,在容器启动时就会创建对象接着调用初始化方法,而多实例是在每次获取的时候创建对象接着调用初始化方法
- 关于销毁:单实例下,容器关闭时调用销毁方法,而多实例下容器不会管理这个bean,也不会调用销毁方法。
通过实现 InitializingBean 和DisposableBean 定义初始化和销毁方法
基本使用:
-
分别实现两接口的 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("初始化..."); } }
-
使用@Bean注入该组件
@Configuration public class TestConfig06 { @Bean(name = "cat") // 注册 public Cat cat() { return new Cat(); } }
JSR 250注解实现:@PostConstant(创建之后) @PreDestroy(销毁之前)
基本使用:
-
组件类定义初始化和销毁方法并加上两注解
public class Dog { public Dog() { System.out.println("创建..."); } // 实例化之后调用 @PostConstruct public void init() { System.out.println("init..."); } // 销毁之前调用 @PreDestroy public void destroy() { System.out.println("destroy..."); } }
-
向容器中注册该组件
@Configuration public class TestConfig07 { @Bean(name = "dog") // 注册 public Dog dog() { return new Dog(); } }
BeanPostProcessor接口——Bean后置处理器
作用:在bean初始化前后进行一些处理工作
BeanPostProcessor 接口内部提供两个方法:
-
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; }
-
postProcessAfterInitialization:类似的,该方法会在我们实现 InitializingBean 的初始化方法 和 @Bean中指定的 init-method 方法调用之后调用:
@Nullable default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; }
基本使用:
-
定义自定义后置处理器(实现 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; } }
-
定义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 ..."); } }
-
向容器中注册Animal,并定义初始化方法
@Configuration @ComponentScan(basePackages = "com.zsp") public class TestConfig08 { @Bean(name = "animal", initMethod = "initMethod", destroyMethod = "destroyMethod") public Animal animal() { return new Animal(); } }
-
测试结果
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
作用:属性赋值
用法:
-
写基本数值:
@Value("张三") private String name;
-
写SpEL表达式
@Value("#{1 + 1}") private Integer id;
-
${} 取出配置文件中的值:该方式在介绍下一个注解时介绍
备注:@Value同样可以用在方法参数上
@PropertySource
作用:类似xml配置方式的< context:property-placeholder >标签,用来定义配置文件的位置并导入配置文件
用法:
-
定义配置文件 teacher.properties,内容如下:
teacher.name=张三 teacher.id=1
-
在配置类中使用 @PropertySource 注入:
@Configuration @ComponentScan("com.zsp.domain") @PropertySource("classpath:teacher.properties") public class TestConfig09 { @Bean public Teacher teacher() { return new Teacher(); } }
-
实体类中:
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
作用:属性注入
基本使用:
-
导包:
<dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency>
-
使用:
@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() {...}
需要注意以下两点:
- 写在类上时,只有是指定环境的时候,整个配置类里面的所有配置才能开始生效。
- 加了环境标识的bean,只有这个环境被激活时才能注册到容器中(默认是default环境)
- 没有标注环境表示的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 { ... }
步骤:
-
写一个监听器来监听某个事件,并注册到容器
@Component public class TestApplicationListener implements ApplicationListener<ApplicationEvent> { @Override public void onApplicationEvent(ApplicationEvent event) { System.out.println(event); } }
-
只要容器中有相关事件的发布,我们就能监听到这个事件。
原理:
事件发布流程:
- 容器创建对象:refresh()
- finishRefresh()
- publishEvent(new ContextRefershedEvent(this))
- 获取事件的多播器(派发器):getApplicationEventMulticaster()
- multicastEvent派发事件
- 获取到所有的ApplicationListener
- 循环
- 如果有Executor,可以支持使用Executor异步派发
- 否则直接执行listener方法:invokeListener()
- 循环
事件多播器(派发器):
- 容器创建对象:refresh()
- initApplicationEventMulticaster():初始化ApplicationEventMulticaster
- 先去容器中找有没有 id="applicationEventMulticaster"的组件
- 如果没有则new SimpleApplicationEventMulticaster(beanFactory),并且加入到容器。我们要在其他组件派发事件,就自动注入这个applicationEventMulticaster;
容器中有哪些监听器:
-
容器创建对象:refresh()
-
registerListeners()
-
从容器中拿到所有的监听器,把他们注册到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("监听....");
}
}
原理:
- 使用EventListenerMethodProcessor处理器来解析方法上的@EventListener
- EventListenerMethodProcessor实现了SmartInitializingSingleton接口
- SmartInitializingSingleton原理:
- ioc容器创建对象并refresh()
- finishBeanFactoryInitialization(beanFactory);初始化剩下的单实例bean
- 先创建所有的单实例bean
- 获取所有创建好的单实例bean,判断是否SmartInitializingSingleton类型的,如果是就调用afterSingletonsInstantiated
附视频学习链接:https://www.bilibili.com/video/BV1oW41167AV
r;
容器中有哪些监听器:
-
容器创建对象:refresh()
-
registerListeners()
-
从容器中拿到所有的监听器,把他们注册到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("监听....");
}
}
原理:
- 使用EventListenerMethodProcessor处理器来解析方法上的@EventListener
- EventListenerMethodProcessor实现了SmartInitializingSingleton接口
- SmartInitializingSingleton原理:
- ioc容器创建对象并refresh()
- finishBeanFactoryInitialization(beanFactory);初始化剩下的单实例bean
- 先创建所有的单实例bean
- 获取所有创建好的单实例bean,判断是否SmartInitializingSingleton类型的,如果是就调用afterSingletonsInstantiated
附视频学习链接:https://www.bilibili.com/video/BV1oW41167AV