因为上一篇文章字数太多,无法更新后续内容,所以重新写了一篇来更新后面的几章(卌六、卌七、卌八、卌九)
目录
卌六、 @Value注入底层
自定义Bean1(用来探究@Value注解中含有${}的情况以及不含${}的情况)、Bean2(用来探究@Value注解中含有 Spring EL 表达式的情况)、Bean3 、Bean4(用来探究@Value 注解中含有#{${}}的情况),具体实现如下:
@Configuration
@SuppressWarnings("all")
public class A46 {
public static void main(String[] args) throws NoSuchFieldException {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(A46.class);
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
ContextAnnotationAutowireCandidateResolver resolver =
new ContextAnnotationAutowireCandidateResolver();
resolver.setBeanFactory(beanFactory);
test1(context, resolver, Bean1.class.getDeclaredField("home"));
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>");
test2(context, resolver, Bean1.class.getDeclaredField("age"));
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>");
test3(context, resolver, Bean2.class.getDeclaredField("bean3"));
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>");
test3(context, resolver, Bean4.class.getDeclaredField("value"));
}
private static void test3(AnnotationConfigApplicationContext context, ContextAnnotationAutowireCandidateResolver resolver, Field field) {
DependencyDescriptor descriptor = new DependencyDescriptor(field,false);
//获取 @Value 的内容
String value = resolver.getSuggestedValue(descriptor).toString();
System.out.println(value);
//解析 ${}
value = context.getEnvironment().resolvePlaceholders(value);
System.out.println(value);
//解析 #{}
Object bean3 = context.getBeanFactory().getBeanExpressionResolver().evaluate(value, new BeanExpressionContext(context.getBeanFactory(), null));
//类型转换
Object result = context.getBeanFactory().getTypeConverter().convertIfNecessary(bean3, descriptor.getDependencyType());
System.out.println(result);
}
private static void test2(AnnotationConfigApplicationContext context, ContextAnnotationAutowireCandidateResolver resolver, Field field) {
DependencyDescriptor descriptor = new DependencyDescriptor(field,false);
//获取 @Value 的内容
String value = resolver.getSuggestedValue(descriptor).toString();
System.out.println(value);
//解析 ${}
value = context.getEnvironment().resolvePlaceholders(value);
System.out.println(value);
Object age = context.getBeanFactory().getTypeConverter().convertIfNecessary(value, descriptor.getDependencyType());
System.out.println(age.getClass());
}
private static void test1(AnnotationConfigApplicationContext context, ContextAnnotationAutowireCandidateResolver resolver, Field field) {
DependencyDescriptor descriptor = new DependencyDescriptor(field,false);
//获取 @Value 的内容
String value = resolver.getSuggestedValue(descriptor).toString();
System.out.println(value);
//解析 ${}
value = context.getEnvironment().resolvePlaceholders(value);
System.out.println(value);
}
public class Bean1{
@Value("${CATALINA_HOME}")
private String home;
@Value("18")
private int age;
}
public class Bean2{
@Value("#{@bean3}") //Spring EL SPEL表达式
private Bean3 bean3;
}
@Component("bean3")
public class Bean3{}
static class Bean4{
@Value("#{'hello,' + '${CATALINA_HOME}'}")
private String value;
}
}
测试结果为:
${CATALINA_HOME}
D:\Tomcat\apache-tomcat-9.0.37
>>>>>>>>>>>>>>>>>>>>>>>>>>>>
18
18
class java.lang.Integer
>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#{@bean3}
#{@bean3}
com.itheima.a46.A46$Bean3@7d9f158f
>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#{'hello,' + '${CATALINA_HOME}'}
#{'hello,' + 'D:\Tomcat\apache-tomcat-9.0.37'}
hello,D:\Tomcat\apache-tomcat-9.0.37
按类型装配的步骤
-
查看需要的类型是否为 Optional,是,则进行封装(非延迟),否则向下走
-
查看需要的类型是否为 ObjectFactory 或 ObjectProvider,是,则进行封装(延迟),否则向下走
-
查看需要的类型(成员或参数)上是否用 @Lazy 修饰,是,则返回代理,否则向下走
-
解析 @Value 的值
-
如果需要的值是字符串,先解析 ${ },再解析 #{ }
-
不是字符串,需要用 TypeConverter 转换
-
-
看需要的类型是否为 Stream、Array、Collection、Map,是,则按集合处理,否则向下走
-
在 BeanFactory 的 resolvableDependencies 中找有没有类型合适的对象注入,没有向下走
-
在 BeanFactory 及父工厂中找类型匹配的 bean 进行筛选,筛选时会考虑 @Qualifier 及泛型
-
结果个数为 0 抛出 NoSuchBeanDefinitionException 异常
-
如果结果 > 1,再根据 @Primary 进行筛选
-
如果结果仍 > 1,再根据成员名或变量名进行筛选
-
结果仍 > 1,抛出 NoUniqueBeanDefinitionException 异常
卌七、@Autowired 注入底层
1. doResolveDependency 外部类型匹配
分别测试五种不同情况下的类型匹配,具体实现如下:
@Configuration
public class A47_1 {
public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A47_1.class);
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>");
//1.根据成员变量的类型注入
DependencyDescriptor dd1 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean2"), false);
System.out.println(beanFactory.doResolveDependency(dd1, "bean1", null, null));
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>");
//2.根据参数类型注入
Method setBean2 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);
DependencyDescriptor dd2 = new DependencyDescriptor(new MethodParameter(setBean2,0), false);
System.out.println(beanFactory.doResolveDependency(dd2, "bean1", null, null));
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>");
//3.结果包装为 Optional<Bean2>
DependencyDescriptor dd3 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean3"),false);
if (dd3.getDependencyType() == Optional.class) {
dd3.increaseNestingLevel();
Object result = beanFactory.doResolveDependency(dd3, "bean1", null, null);
System.out.println(Optional.ofNullable(result));
}
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>");
//4.结果包装为 ObjectProvider ,ObjectFactory
DependencyDescriptor dd4 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean4"),false);
if (dd4.getDependencyType() == ObjectFactory.class) {
dd4.increaseNestingLevel();
ObjectFactory objectFactory = new ObjectFactory() {
@Override
public Object getObject() throws BeansException {
Object result = beanFactory.doResolveDependency(dd4, "bean1", null, null);
return result;
}
};
System.out.println(objectFactory.getObject());
}
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>");
//5. 对 @Lazy 的处理 (创建代理对象)
DependencyDescriptor dd5 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean2"),false);
ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
resolver.setBeanFactory(beanFactory);
Object proxy = resolver.getLazyResolutionProxyIfNecessary(dd5, "bean1");
System.out.println(proxy);
System.out.println(proxy.getClass());
}
static class Bean1{
@Autowired @Lazy
private Bean2 bean2;
@Autowired
public void setBean2(Bean2 bean2){
this.bean2 = bean2;
}
@Autowired
private Optional<Bean2> bean3;
@Autowired
private ObjectFactory<Bean2> bean4;
}
@Component("bean2")
static class Bean2{
@Override
public String toString() {
return super.toString();
}
}
}
测试结果为:
>>>>>>>>>>>>>>>>>>>>>>>>>>>
com.itheima.a47.A47_1$Bean2@536f2a7e
>>>>>>>>>>>>>>>>>>>>>>>>>>>
com.itheima.a47.A47_1$Bean2@536f2a7e
>>>>>>>>>>>>>>>>>>>>>>>>>>>
Optional[com.itheima.a47.A47_1$Bean2@536f2a7e]
>>>>>>>>>>>>>>>>>>>>>>>>>>>
com.itheima.a47.A47_1$Bean2@536f2a7e
>>>>>>>>>>>>>>>>>>>>>>>>>>>
com.itheima.a47.A47_1$Bean2@536f2a7e
class com.itheima.a47.A47_1$Bean2$$EnhancerBySpringCGLIB$$537a559d
2.doResolveDependency 内部类型匹配
分别测试 数组类型、List类型、ApplicationContext、泛型、@Qualifier:
@Configuration
public class A47_2 {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A47_2.class);
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
System.out.println(">>>>>>>>>>>>>>>>>>> 1.数组类型");
testArray(beanFactory);
System.out.println(">>>>>>>>>>>>>>>>>>> 2.List类型");
testList(beanFactory);
System.out.println(">>>>>>>>>>>>>>>>>>> 3.applicationContext");
testApplicationContext(beanFactory);
System.out.println(">>>>>>>>>>>>>>>>>>> 4.泛型");
testGeneric(beanFactory);
System.out.println(">>>>>>>>>>>>>>>>>>> 5.@Qualifier");
testQualifier(beanFactory);
}
private static void testQualifier(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
DependencyDescriptor dd5 = new DependencyDescriptor(Target.class.getDeclaredField("service"),true);
Class<?> dependencyType = dd5.getDependencyType();
ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
resolver.setBeanFactory(beanFactory);
String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, dependencyType);
for (String name : names) {
BeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition(name);
if (resolver.isAutowireCandidate(new BeanDefinitionHolder(beanDefinition,name), dd5)) {
System.out.println(name);
System.out.println(dd5.resolveCandidate(name, dependencyType, beanFactory));
}
}
}
private static void testGeneric(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
DependencyDescriptor dd4 = new DependencyDescriptor(Target.class.getDeclaredField("dao"),true);
Class<?> dependencyType = dd4.getDependencyType();
ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
resolver.setBeanFactory(beanFactory);
for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, dependencyType)) {
BeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition(name);
//对此 BeanDefinition 和 DependencyDescriptor 的泛型是否一致
if (resolver.isAutowireCandidate(new BeanDefinitionHolder(beanDefinition,name), dd4)) {
System.out.println(name);
System.out.println(dd4.resolveCandidate(name, dependencyType, beanFactory));
}
}
}
private static void testApplicationContext(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException, IllegalAccessException {
DependencyDescriptor dd3 = new DependencyDescriptor(Target.class.getDeclaredField("applicationContext"), true);
Field resolvableDependencies = DefaultListableBeanFactory.class.getDeclaredField("resolvableDependencies");
resolvableDependencies.setAccessible(true);
Map<Class<?>,Object> dependencies = (Map<Class<?>, Object>) resolvableDependencies.get(beanFactory);
for (Map.Entry<Class<?>, Object> entry : dependencies.entrySet()) {
//左边类型 右边类型 ---> 看右边类型是否属于左边类型
if (entry.getKey().isAssignableFrom(dd3.getDependencyType())) {
System.out.println(entry.getValue());
break;
}
}
}
private static void testList(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
DependencyDescriptor dd2 = new DependencyDescriptor(Target.class.getDeclaredField("serviceList"),true);
if (dd2.getDependencyType() == List.class) {
Class<?> resolve = dd2.getResolvableType().getGeneric().resolve();
System.out.println(resolve);
List<Object> list = new ArrayList<>();
String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, resolve);
for (String name : names) {
Object bean = dd2.resolveCandidate(name, resolve, beanFactory);
list.add(bean);
}
System.out.println(list);
}
}
private static void testArray(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
DependencyDescriptor dd1 = new DependencyDescriptor(Target.class.getDeclaredField("serviceArray"), true);
if (dd1.getDependencyType().isArray()) {
Class<?> componentType = dd1.getDependencyType().getComponentType();
System.out.println(componentType);
String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, componentType);
List<Object> beans = new ArrayList<>();
for (String name : names) {
System.out.println(name);
Object bean = dd1.resolveCandidate(name, componentType, beanFactory);
beans.add(bean);
}
Object array = beanFactory.getTypeConverter().convertIfNecessary(beans, dd1.getDependencyType());
System.out.println(array);
}
}
static class Target{
@Autowired private Service[] serviceArray;
@Autowired private List<Service> serviceList;
@Autowired private ConfigurableApplicationContext applicationContext;
@Autowired private Dao<Teacher> dao;
@Autowired @Qualifier("service2") private Service service;
}
interface Service{}
@Component("service1")
static class Service1 implements Service{}
@Component("service2")
static class Service2 implements Service{}
@Component("service3")
static class Service3 implements Service{}
interface Dao<T>{}
@Component("dao1")
static class Dao1 implements Dao<Student>{}
@Component("dao2")
static class Dao2 implements Dao<Teacher>{}
static class Student{}
static class Teacher{}
}
测试结果为:
>>>>>>>>>>>>>>>>>>> 1.数组类型
interface com.itheima.a47.A47_2$Service
service3
service2
service1
[Lcom.itheima.a47.A47_2$Service;@2de56eb2
>>>>>>>>>>>>>>>>>>> 2.List类型
interface com.itheima.a47.A47_2$Service
[com.itheima.a47.A47_2$Service3@3feb2dda, com.itheima.a47.A47_2$Service2@6a8658ff, com.itheima.a47.A47_2$Service1@1c742ed4]
>>>>>>>>>>>>>>>>>>> 3.applicationContext
org.springframework.context.annotation.AnnotationConfigApplicationContext@70a9f84e, started on Sat Jul 23 16:05:30 CST 2022
>>>>>>>>>>>>>>>>>>> 4.泛型
dao2
com.itheima.a47.A47_2$Dao2@6f43c82
>>>>>>>>>>>>>>>>>>> 5.@Qualifier
service2
com.itheima.a47.A47_2$Service2@6a8658ff
进程已结束,退出代码为 0
测试@Primary、默认情况(与成员变量名或方法参数名相同bean):
@Configuration
public class A47_3 {
public static void main(String[] args) throws NoSuchFieldException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A47_3.class);
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
testPrimary(beanFactory);
testDefault(beanFactory);
}
private static void testDefault(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
DependencyDescriptor descriptor = new DependencyDescriptor(Target2.class.getDeclaredField("service3"), false);
Class<?> dependencyType = descriptor.getDependencyType();
for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, dependencyType)) {
if (name.equals(descriptor.getDependencyName())){
System.out.println(name);
}
}
}
private static void testPrimary(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
DependencyDescriptor descriptor = new DependencyDescriptor(Target1.class.getDeclaredField("service"),false);
Class<?> dependencyType = descriptor.getDependencyType();
for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, dependencyType)) {
if (beanFactory.getMergedBeanDefinition(name).isPrimary()) {
System.out.println(name);
}
}
}
static class Target1{
@Autowired private Service service;
}
static class Target2{
@Autowired private Service service3;
}
interface Service{}
@Component("service1")
static class Service1 implements Service{}
@Component("servcie2") @Primary
static class Service2 implements Service{}
@Component("service3")
static class Service3 implements Service{}
}
测试结果为:
servcie2
service3
总结:
-
@Autowired 本质上是根据成员变量或方法参数的类型进行装配
-
如果待装配类型是 Optional,需要根据 Optional 泛型找到 bean,再封装为 Optional 对象装配
-
如果待装配的类型是 ObjectFactory,需要根据 ObjectFactory 泛型创建 ObjectFactory 对象装配
-
此方法可以延迟 bean 的获取
-
-
如果待装配的成员变量或方法参数上用 @Lazy 标注,会创建代理对象装配
-
此方法可以延迟真实 bean 的获取
-
被装配的代理不作为 bean
-
-
如果待装配类型是数组,需要获取数组元素类型,根据此类型找到多个 bean 进行装配
-
如果待装配类型是 Collection 或其子接口,需要获取 Collection 泛型,根据此类型找到多个 bean
-
如果待装配类型是 ApplicationContext 等特殊类型
-
会在 BeanFactory 的 resolvableDependencies 成员按类型查找装配
-
resolvableDependencies 是 map 集合,key 是特殊类型,value 是其对应对象
-
不能直接根据 key 进行查找,而是用 isAssignableFrom 逐一尝试右边类型是否可以被赋值给左边的 key 类型
-
-
如果待装配类型有泛型参数
-
需要利用 ContextAnnotationAutowireCandidateResolver 按泛型参数类型筛选
-
-
如果待装配类型有 @Qualifier
-
需要利用 ContextAnnotationAutowireCandidateResolver 按注解提供的 bean 名称筛选
-
-
有 @Primary 标注的 @Component 或 @Bean 的处理
-
与成员变量名或方法参数名同名 bean 的处理
卌八、事件监听器
1.实现ApplicationListener接口
下面是一个问题实例:在执行主线任务的同时,会同时进行支线任务--发送短信和发送邮件,这就导致耦合度过高,无法进行更新或者舍弃支线任务,所以此时就需要添加事件监听器来进行解耦
@Configuration
public class A48_1 {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A48_1.class);
context.getBean(MyService.class).doBusiness();
context.close();
}
static class MyEvent extends ApplicationEvent{
public MyEvent(Object source) {
super(source);
}
}
@Component
static class MyService{
private static final Logger log = LoggerFactory.getLogger(MyService.class);
@Autowired
private ApplicationEventPublisher publisher;//applicationContext
public void doBusiness(){
log.debug("主线任务");
//主线任务完成后需要做一些支线任务,下面是问题代码
log.debug("发送短信");
log.debug("发送邮件");
}
}
}
添加事件监听器:
@Configuration
public class A48_1 {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A48_1.class);
context.getBean(MyService.class).doBusiness();
context.close();
}
static class MyEvent extends ApplicationEvent{
public MyEvent(Object source) {
super(source);
}
}
@Component
static class MyService{
private static final Logger log = LoggerFactory.getLogger(MyService.class);
@Autowired
private ApplicationEventPublisher publisher;//applicationContext
public void doBusiness(){
log.debug("主线任务");
//主线任务完成后需要做一些支线任务,下面是问题代码
publisher.publishEvent(new MyEvent("MyService.doBusiness()"));
}
}
@Component
static class SmsApplicationListener implements ApplicationListener<MyEvent>{
private static final Logger log = LoggerFactory.getLogger(SmsApplicationListener.class);
@Override
public void onApplicationEvent(MyEvent event) {
log.debug("发送短信");
}
}
@Component
static class EmailApplicationListener implements ApplicationListener<MyEvent>{
private static final Logger log = LoggerFactory.getLogger(EmailApplicationListener.class);
@Override
public void onApplicationEvent(MyEvent event) {
log.debug("发送邮件");
}
}
}
测试结果:
[DEBUG] 09:14:15.964 [main] com.itheima.a48.A48_1$MyService - 主线任务
[DEBUG] 09:14:15.974 [main] c.i.a.A48_1$EmailApplicationListener - 发送邮件
[DEBUG] 09:14:15.974 [main] c.i.a.A48_1$SmsApplicationListener - 发送短信
2.使用@EventListener注解
接下来对上述代码进行优化--默认是单线程发送事件,通过配置线程池来异步发送事件
@Configuration
public class A48_2 {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A48_2.class);
context.getBean(MyService.class).doBusiness();
context.close();
}
static class MyEvent extends ApplicationEvent{
public MyEvent(Object source) {
super(source);
}
}
@Component
static class MyService{
private static final Logger log = LoggerFactory.getLogger(MyService.class);
@Autowired //ApplicationEventPublisher 底层是使用 ApplicationEventMulticaster
private ApplicationEventPublisher publisher;//applicationContext
public void doBusiness(){
log.debug("主线任务");
//主线任务完成后需要做一些支线任务,下面是问题代码
publisher.publishEvent(new MyEvent("MyService.doBusiness()"));
}
}
@Component
static class SmsService{
private static final Logger log = LoggerFactory.getLogger(SmsService.class);
@EventListener
public void listener(MyEvent myEvent){
log.debug("发送短信");
}
}
@Component
static class EmailService{
private static final Logger log = LoggerFactory.getLogger(EmailService.class);
@EventListener
public void listener(MyEvent myEvent){
log.debug("发送邮件");
}
}
@Bean //设置线程池对象
public ThreadPoolTaskExecutor executor(){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(3);//设置核心线程数量
executor.setMaxPoolSize(10);//设置最大线程数
executor.setQueueCapacity(100);//设置队列大小
return executor;
}
@Bean//默认是单线程发送事件,配置线程池,利用线程池来异步发送事件
public SimpleApplicationEventMulticaster applicationEventMulticaster(ThreadPoolTaskExecutor executor){
SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
multicaster.setTaskExecutor(executor);
return multicaster;
}
}
测试结果为:
[DEBUG] 09:28:30.739 [main] com.itheima.a48.A48_2$MyService - 主线任务
[DEBUG] 09:28:30.748 [executor-1] com.itheima.a48.A48_2$EmailService - 发送邮件
[DEBUG] 09:28:30.748 [executor-2] com.itheima.a48.A48_2$SmsService - 发送短信
3.自定义注解
SmartInitializingSingleton :在所有单例初始化完成后,解析每个单例bean
@Configuration
public class A48_3 {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A48_3.class);
context.getBean(MyService.class).doBusiness();
context.close();
}
@Bean
public SmartInitializingSingleton smartInitializingSingleton(ConfigurableApplicationContext context){
return new SmartInitializingSingleton() {
@Override
public void afterSingletonsInstantiated() {
for (String name : context.getBeanDefinitionNames()) {
Object bean = context.getBean(name);
for (Method method : bean.getClass().getMethods()) {
if (method.isAnnotationPresent(MyListener.class)) {
ApplicationListener listener = new ApplicationListener() {
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println(event);
Class<?> eventType = method.getParameterTypes()[0];//监听器方法需要的事件类型
if (eventType.isAssignableFrom(event.getClass())) {
try {
method.invoke(bean, event);
} catch (Exception e) {
e.printStackTrace();
}
}
}
};
context.addApplicationListener(listener);
}
}
}
}
};
}
static class MyEvent extends ApplicationEvent{
public MyEvent(Object source) {
super(source);
}
}
@Component
static class MyService{
private static final Logger log = LoggerFactory.getLogger(MyService.class);
@Autowired //ApplicationEventPublisher 底层是使用 ApplicationEventMulticaster
private ApplicationEventPublisher publisher;//applicationContext
public void doBusiness(){
log.debug("主线任务");
//主线任务完成后需要做一些支线任务,下面是问题代码
publisher.publishEvent(new MyEvent("MyService.doBusiness()"));
}
}
@Component
static class SmsService{
private static final Logger log = LoggerFactory.getLogger(SmsService.class);
@MyListener
public void listener(MyEvent myEvent){
log.debug("发送短信");
}
}
@Component
static class EmailService{
private static final Logger log = LoggerFactory.getLogger(EmailService.class);
@MyListener
public void listener(MyEvent myEvent){
log.debug("发送邮件");
}
}
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyListener{}
}
测试结果为:
org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@1188e820, started on Sun Jul 24 09:33:27 CST 2022]
org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@1188e820, started on Sun Jul 24 09:33:27 CST 2022]
[DEBUG] 09:33:27.690 [main] com.itheima.a48.A48_3$MyService - 主线任务
com.itheima.a48.A48_3$MyEvent[source=MyService.doBusiness()]
[DEBUG] 09:33:27.698 [main] com.itheima.a48.A48_3$EmailService - 发送邮件
com.itheima.a48.A48_3$MyEvent[source=MyService.doBusiness()]
[DEBUG] 09:33:27.698 [main] com.itheima.a48.A48_3$SmsService - 发送短信
org.springframework.context.event.ContextClosedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@1188e820, started on Sun Jul 24 09:33:27 CST 2022]
org.springframework.context.event.ContextClosedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@1188e820, started on Sun Jul 24 09:33:27 CST 2022]
卌九、事件发布器
模拟事件发布器的实现:
自定义AbstractApplicationEventMulticaster 类来实现 ApplicationEventMulticaster接口,对其接口内的方法进行一个空实现。addApplicationListenerBean 负责收集容器中的监听器,监听器会统一转换为 GenericApplicationListener 对象(是ApplicationListener的一个子接口),以支持判断事件类型
@Configuration
@SuppressWarnings("all")
public class A49 {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A49.class);
context.getBean(MyService.class).doBusiness();
context.close();
}
static class MyEvent extends ApplicationEvent {
public MyEvent(Object source) {
super(source);
}
}
@Component
static class MyService{
private static final Logger log = LoggerFactory.getLogger(MyService.class);
@Autowired //ApplicationEventPublisher 底层是使用 ApplicationEventMulticaster
private ApplicationEventPublisher publisher;//applicationContext
public void doBusiness(){
log.debug("主线任务");
//主线任务完成后需要做一些支线任务,下面是问题代码
publisher.publishEvent(new MyEvent("MyService.doBusiness()"));
}
}
@Component
static class SmsApplicationListener implements ApplicationListener<MyEvent>{
private static final Logger log = LoggerFactory.getLogger(SmsApplicationListener.class);
@Override
public void onApplicationEvent(MyEvent event) {
log.debug("发送短信");
}
}
@Component
static class EmailApplicationListener implements ApplicationListener<MyEvent>{
private static final Logger log = LoggerFactory.getLogger(EmailApplicationListener.class);
@Override
public void onApplicationEvent(MyEvent event) {
log.debug("发送邮件");
}
}
@Bean //设置线程池对象
public ThreadPoolTaskExecutor executor(){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(3);//设置核心线程数量
executor.setMaxPoolSize(10);//设置最大线程数
executor.setQueueCapacity(100);//设置队列大小
return executor;
}
@Bean
public ApplicationEventMulticaster applicationEventMulticaster(ConfigurableApplicationContext context,ThreadPoolTaskExecutor executor){
return new AbstractApplicationEventMulticaster() {
private List<GenericApplicationListener> listeners = new ArrayList<>();
@Override //收集监听器
public void addApplicationListenerBean(String name) {
ApplicationListener listener = context.getBean(name, ApplicationListener.class);
System.out.println(listener);
//获取该监听器支持的事件类型
ResolvableType type = ResolvableType.forClass(listener.getClass()).getInterfaces()[0].getGeneric();
System.out.println(type);
//将原始的 listener 封装为 支持事件类型检查的 GenericApplicationListener
GenericApplicationListener genericApplicationListener = new GenericApplicationListener() {
@Override //是否支持某事件类型 真实的事件类型
public boolean supportsEventType(ResolvableType eventType) {
return type.isAssignableFrom(eventType);
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
executor.submit(() -> listener.onApplicationEvent(event));
}
};
listeners.add(genericApplicationListener);
}
@Override //发布事件
public void multicastEvent(ApplicationEvent event, ResolvableType eventType) {
for (GenericApplicationListener listener : listeners) {
if (listener.supportsEventType(ResolvableType.forClass(event.getClass()))) {
listener.onApplicationEvent(event);
}
}
}
};
}
abstract static class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster{
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
}
@Override
public void addApplicationListenerBean(String listenerBeanName) {
}
@Override
public void removeApplicationListener(ApplicationListener<?> listener) {
}
@Override
public void removeApplicationListenerBean(String listenerBeanName) {
}
@Override
public void removeApplicationListeners(Predicate<ApplicationListener<?>> predicate) {
}
@Override
public void removeApplicationListenerBeans(Predicate<String> predicate) {
}
@Override
public void removeAllListeners() {
}
@Override
public void multicastEvent(ApplicationEvent event) {
}
@Override
public void multicastEvent(ApplicationEvent event, ResolvableType eventType) {
}
}
}
测试结果:
com.itheima.a49.A49$EmailApplicationListener@68c9d179
com.itheima.a49.A49$MyEvent
com.itheima.a49.A49$SmsApplicationListener@4d15107f
com.itheima.a49.A49$MyEvent
[DEBUG] 09:54:50.113 [main] com.itheima.a49.A49$MyService - 主线任务
[DEBUG] 09:54:50.125 [executor-1] c.i.a.A49$EmailApplicationListener - 发送邮件
[DEBUG] 09:54:50.125 [executor-2] c.i.a49.A49$SmsApplicationListener - 发送短信
总结:
-
addApplicationListenerBean 负责收集容器中的监听器
-
监听器会统一转换为 GenericApplicationListener 对象,以支持判断事件类型
-
-
multicastEvent 遍历监听器集合,发布事件
-
发布前先通过 GenericApplicationListener.supportsEventType 判断支持该事件类型才发事件
-
可以利用线程池进行异步发事件优化
-
-
如果发送的事件对象不是 ApplicationEvent 类型,Spring 会把它包装为 PayloadApplicationEvent 并用泛型技术解析事件对象的原始类型
到此,本次 深度学习Spring5底层原理随笔 到此完结,第一次写长篇博客,有任何不足,请大佬指教!(共252504字)