深度学习Spring5底层原理(黑马学习随笔)--续

因为上一篇文章字数太多,无法更新后续内容,所以重新写了一篇来更新后面的几章(卌六、卌七、卌八、卌九)

目录

卌六、 @Value注入底层 

卌七、@Autowired 注入底层

1. doResolveDependency 外部类型匹配

2.doResolveDependency 内部类型匹配

卌八、事件监听器

1.实现ApplicationListener接口

2.使用@EventListener注解

3.自定义注解

卌九、事件发布器


卌六、 @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

按类型装配的步骤

  1. 查看需要的类型是否为 Optional,是,则进行封装(非延迟),否则向下走

  2. 查看需要的类型是否为 ObjectFactory ObjectProvider,是,则进行封装(延迟),否则向下走

  3. 查看需要的类型(成员或参数)上是否用 @Lazy 修饰,是,则返回代理,否则向下走

  4. 解析 @Value 的值

    1. 如果需要的值是字符串,先解析 ${ },再解析 #{ }

    2. 不是字符串,需要用 TypeConverter 转换

  5. 看需要的类型是否为 Stream、Array、Collection、Map,是,则按集合处理,否则向下走

  6. BeanFactoryresolvableDependencies 中找有没有类型合适的对象注入,没有向下走

  7. BeanFactory 及父工厂中找类型匹配的 bean 进行筛选,筛选时会考虑 @Qualifier 及泛型

  8. 结果个数为 0 抛出 NoSuchBeanDefinitionException 异常

  9. 如果结果 > 1,再根据 @Primary 进行筛选

  10. 如果结果仍 > 1,再根据成员名或变量名进行筛选

  11. 结果仍 > 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

总结:

  1. @Autowired 本质上是根据成员变量或方法参数的类型进行装配

  2. 如果待装配类型是 Optional,需要根据 Optional 泛型找到 bean,再封装为 Optional 对象装配

  3. 如果待装配的类型是 ObjectFactory,需要根据 ObjectFactory 泛型创建 ObjectFactory 对象装配

    • 此方法可以延迟 bean 的获取

  4. 如果待装配的成员变量或方法参数上用 @Lazy 标注,会创建代理对象装配

    • 此方法可以延迟真实 bean 的获取

    • 被装配的代理不作为 bean

  5. 如果待装配类型是数组,需要获取数组元素类型,根据此类型找到多个 bean 进行装配

  6. 如果待装配类型是 Collection 或其子接口,需要获取 Collection 泛型,根据此类型找到多个 bean

  7. 如果待装配类型是 ApplicationContext 等特殊类型

    • 会在 BeanFactoryresolvableDependencies 成员按类型查找装配

    • resolvableDependencies 是 map 集合,key 是特殊类型,value 是其对应对象

    • 不能直接根据 key 进行查找,而是用 isAssignableFrom 逐一尝试右边类型是否可以被赋值给左边的 key 类型

  8. 如果待装配类型有泛型参数

    • 需要利用 ContextAnnotationAutowireCandidateResolver 按泛型参数类型筛选

  9. 如果待装配类型有 @Qualifier

    • 需要利用 ContextAnnotationAutowireCandidateResolver 按注解提供的 bean 名称筛选

  10. @Primary 标注的 @Component 或 @Bean 的处理

  11. 与成员变量名或方法参数名同名 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  - 发送短信 

总结:

  1. addApplicationListenerBean 负责收集容器中的监听器

    • 监听器会统一转换为 GenericApplicationListener 对象,以支持判断事件类型

  2. multicastEvent 遍历监听器集合,发布事件

    • 发布前先通过 GenericApplicationListener.supportsEventType 判断支持该事件类型才发事件

    • 可以利用线程池进行异步发事件优化

  3. 如果发送的事件对象不是 ApplicationEvent 类型,Spring 会把它包装为 PayloadApplicationEvent 并用泛型技术解析事件对象的原始类型

到此,本次 深度学习Spring5底层原理随笔 到此完结,第一次写长篇博客,有任何不足,请大佬指教!(共252504字)

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值