• spring高级源码50讲-43-50(spring续)


    其它

    43) FactoryBean

    演示 - FactoryBean
    代码参考
    package com.itheima.a43;
    
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.annotation.ComponentScan;
    
    @ComponentScan
    public class A43 {
    
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A43.class);
    
            Bean1 bean1 = (Bean1) context.getBean("bean1");
            Bean1 bean2 = (Bean1) context.getBean("bean1");
            Bean1 bean3 = (Bean1) context.getBean("bean1");
            System.out.println(bean1);
            System.out.println(bean2);
            System.out.println(bean3);
    
            System.out.println(context.getBean(Bean1.class));
    
            System.out.println(context.getBean(Bean1FactoryBean.class));
            System.out.println(context.getBean("&bean1"));
    
            context.close();
    
            /*
                学到了什么: 一个在 Spring 发展阶段中重要, 但目前已经很鸡肋的接口 FactoryBean 的使用要点
                说它鸡肋有两点:
                    1. 它的作用是用制造创建过程较为复杂的产品, 如 SqlSessionFactory, 但 @Bean 已具备等价功能
                    2. 使用上较为古怪, 一不留神就会用错
                        a. 被 FactoryBean 创建的产品
                            - 会认为创建、依赖注入、Aware 接口回调、前初始化这些都是 FactoryBean 的职责, 这些流程都不会走
                            - 唯有后初始化的流程会走, 也就是产品可以被代理增强
                            - 单例的产品不会存储于 BeanFactory 的 singletonObjects 成员中, 而是另一个 factoryBeanObjectCache 成员中
                        b. 按名字去获取时, 拿到的是产品对象, 名字前面加 & 获取的是工厂对象
                就说恶心不?
    
                但目前此接口的实现仍被大量使用, 想被全面废弃很难
             */
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    package com.itheima.a43;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.beans.factory.BeanFactoryAware;
    import org.springframework.beans.factory.annotation.Autowired;
    
    import javax.annotation.PostConstruct;
    
    public class Bean1 implements BeanFactoryAware {
        private static final Logger log = LoggerFactory.getLogger(Bean1.class);
    
        private Bean2 bean2;
    
        @Autowired
        public void setBean2(Bean2 bean2) {
            log.debug("setBean2({})", bean2);
            this.bean2 = bean2;
        }
    
        public Bean2 getBean2() {
            return bean2;
        }
    
        @PostConstruct
        public void init() {
            log.debug("init");
        }
    
        @Override
        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
            log.debug("setBeanFactory({})", beanFactory);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    package com.itheima.a43;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.FactoryBean;
    import org.springframework.stereotype.Component;
    
    @Component("bean1")
    public class Bean1FactoryBean implements FactoryBean<Bean1> {
    
        private static final Logger log = LoggerFactory.getLogger(Bean1FactoryBean.class);
    
        // 决定了根据【类型】获取或依赖注入能否成功
        @Override
        public Class<?> getObjectType() {
            return Bean1.class;
        }
    
        // 决定了 getObject() 方法被调用一次还是多次
        @Override
        public boolean isSingleton() {
            return true;
        }
    
        @Override
        public Bean1 getObject() throws Exception {
            Bean1 bean1 = new Bean1();
            log.debug("create bean: {}", bean1);
            return bean1;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    收获💡
    1. 它的作用是用制造创建过程较为复杂的产品, 如 SqlSessionFactory, 但 @Bean 已具备等价功能
    2. 使用上较为古怪, 一不留神就会用错
      1. 被 FactoryBean 创建的产品
        • 会认为创建、依赖注入、Aware 接口回调、前初始化这些都是 FactoryBean 的职责, 这些流程都不会走
        • 唯有后初始化的流程会走, 也就是产品可以被代理增强
        • 单例的产品不会存储于 BeanFactory 的 singletonObjects 成员中, 而是另一个 factoryBeanObjectCache 成员中
      2. 按名字去获取时, 拿到的是产品对象, 名字前面加 & 获取的是工厂对象

    44) @Indexed 原理

    真实项目中,只需要加入以下依赖即可

    <dependency>
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-context-indexerartifactId>
        <optional>trueoptional>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    演示 - @Indexed
    代码参考
    package com.itheima.a44;
    
    import org.springframework.beans.factory.support.DefaultListableBeanFactory;
    import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
    
    import java.io.IOException;
    import java.lang.reflect.InvocationTargetException;
    
    /*
        做这个试验前, 先在 target/classes 创建 META-INF/spring.components, 内容为
    
        com.itheima.a44.Bean1=org.springframework.stereotype.Component
        com.itheima.a44.Bean2=org.springframework.stereotype.Component
    
        做完实现建议删除, 避免影响其它组件扫描的结果
    
        真实项目中, 这个步骤可以自动完成, 加入以下依赖
        
            org.springframework
            spring-context-indexer
            true
        
     */
    public class A44 {
        public static void main(String[] args) throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
            DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
            // 组件扫描的核心类
            ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(beanFactory);
    
            scanner.scan(A44.class.getPackageName());
    
            for (String name : beanFactory.getBeanDefinitionNames()) {
                System.out.println(name);
            }
    
            /*
                学到了什么
                    a. @Indexed 的原理, 在编译时就根据 @Indexed 生成 META-INF/spring.components 文件
                    扫描时
                    1. 如果发现 META-INF/spring.components 存在, 以它为准加载 bean definition
                    2. 否则, 会遍历包下所有 class 资源 (包括 jar 内的)
             */
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    收获💡
    1. 在编译时就根据 @Indexed 生成 META-INF/spring.components 文件
    2. 扫描时
      • 如果发现 META-INF/spring.components 存在, 以它为准加载 bean definition
      • 否则, 会遍历包下所有 class 资源 (包括 jar 内的)
    3. 解决的问题,在编译期就找到 @Component 组件,节省运行期间扫描 @Component 的时间

    45) 代理进一步理解

    演示 - 代理
    代码参考
    package com.itheima.a45;
    
    import org.springframework.aop.framework.Advised;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.ConfigurableApplicationContext;
    
    import java.lang.reflect.Method;
    
    @SpringBootApplication
    public class A45 {
    
        public static void main(String[] args) throws Exception {
            ConfigurableApplicationContext context = SpringApplication.run(A45.class, args);
    
            Bean1 proxy = context.getBean(Bean1.class);
    
    
    
            /*
                1.演示 spring 代理的设计特点
                    依赖注入和初始化影响的是原始对象
                    代理与目标是两个对象,二者成员变量并不共用数据
             */
    //        showProxyAndTarget(proxy);
    //
    //        System.out.println(">>>>>>>>>>>>>>>>>>>");
    //        System.out.println(proxy.getBean2());
    //        System.out.println(proxy.isInitialized());
    
            /*
                2.演示 static 方法、final 方法、private 方法均无法增强
             */
    
            proxy.m1();
            proxy.m2();
            proxy.m3();
            Method m4 = Bean1.class.getDeclaredMethod("m1");
            m4.setAccessible(true);
            m4.invoke(proxy);
    
            context.close();
        }
    
    
        public static void showProxyAndTarget(Bean1 proxy) throws Exception {
            System.out.println(">>>>> 代理中的成员变量");
            System.out.println("\tinitialized=" + proxy.initialized);
            System.out.println("\tbean2=" + proxy.bean2);
    
            if (proxy instanceof Advised advised) {
                System.out.println(">>>>> 目标中的成员变量");
                Bean1 target = (Bean1) advised.getTargetSource().getTarget();
                System.out.println("\tinitialized=" + target.initialized);
                System.out.println("\tbean2=" + target.bean2);
            }
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    收获💡
    1. spring 代理的设计特点

      • 依赖注入和初始化影响的是原始对象

        • 因此 cglib 不能用 MethodProxy.invokeSuper()
      • 代理与目标是两个对象,二者成员变量并不共用数据

    2. static 方法、final 方法、private 方法均无法增强

      • 进一步理解代理增强基于方法重写

    46) @Value 装配底层

    按类型装配的步骤
    1. 查看需要的类型是否为 Optional,是,则进行封装(非延迟),否则向下走
    2. 查看需要的类型是否为 ObjectFactory 或 ObjectProvider,是,则进行封装(延迟),否则向下走
    3. 查看需要的类型(成员或参数)上是否用 @Lazy 修饰,是,则返回代理,否则向下走
    4. 解析 @Value 的值
      1. 如果需要的值是字符串,先解析 ${ },再解析 #{ }
      2. 不是字符串,需要用 TypeConverter 转换
    5. 看需要的类型是否为 Stream、Array、Collection、Map,是,则按集合处理,否则向下走
    6. 在 BeanFactory 的 resolvableDependencies 中找有没有类型合适的对象注入,没有向下走
    7. 在 BeanFactory 及父工厂中找类型匹配的 bean 进行筛选,筛选时会考虑 @Qualifier 及泛型
    8. 结果个数为 0 抛出 NoSuchBeanDefinitionException 异常
    9. 如果结果 > 1,再根据 @Primary 进行筛选
    10. 如果结果仍 > 1,再根据成员名或变量名进行筛选
    11. 结果仍 > 1,抛出 NoUniqueBeanDefinitionException 异常
    演示 - @Value 装配过程
    代码参考
    package com.itheima.a46;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.beans.factory.config.BeanExpressionContext;
    import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
    import org.springframework.beans.factory.config.DependencyDescriptor;
    import org.springframework.beans.factory.support.DefaultListableBeanFactory;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
    import org.springframework.stereotype.Component;
    
    import java.lang.reflect.Field;
    
    // 本章节作为第四讲的延续
    @Configuration
    @SuppressWarnings("all")
    public class A46 {
    
        public static void main(String[] args) throws Exception {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A46.class);
            DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
    
            ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
            resolver.setBeanFactory(beanFactory);
    
    //        test1(context, resolver, Bean1.class.getDeclaredField("home"));
    //        test2(context, resolver, Bean1.class.getDeclaredField("age"));
    //        test3(context, resolver, Bean2.class.getDeclaredField("bean3"));
            test3(context, resolver, Bean4.class.getDeclaredField("value"));
        }
    
        private static void test3(AnnotationConfigApplicationContext context, ContextAnnotationAutowireCandidateResolver resolver, Field field) {
            DependencyDescriptor dd1 = new DependencyDescriptor(field, false);
            // 获取 @Value 的内容
            String value = resolver.getSuggestedValue(dd1).toString();
            System.out.println(value);
    
            // 解析 ${}
            value = context.getEnvironment().resolvePlaceholders(value);
            System.out.println(value);
            System.out.println(value.getClass());
    
            // 解析 #{} @bean3
            Object bean3 = context.getBeanFactory().getBeanExpressionResolver().evaluate(value, new BeanExpressionContext(context.getBeanFactory(), null));
    
            // 类型转换
            Object result = context.getBeanFactory().getTypeConverter().convertIfNecessary(bean3, dd1.getDependencyType());
            System.out.println(result);
        }
    
        private static void test2(AnnotationConfigApplicationContext context, ContextAnnotationAutowireCandidateResolver resolver, Field field) {
            DependencyDescriptor dd1 = new DependencyDescriptor(field, false);
            // 获取 @Value 的内容
            String value = resolver.getSuggestedValue(dd1).toString();
            System.out.println(value);
    
            // 解析 ${}
            value = context.getEnvironment().resolvePlaceholders(value);
            System.out.println(value);
            System.out.println(value.getClass());
            Object age = context.getBeanFactory().getTypeConverter().convertIfNecessary(value, dd1.getDependencyType());
            System.out.println(age.getClass());
        }
    
        private static void test1(AnnotationConfigApplicationContext context, ContextAnnotationAutowireCandidateResolver resolver, Field field) {
            DependencyDescriptor dd1 = new DependencyDescriptor(field, false);
            // 获取 @Value 的内容
            String value = resolver.getSuggestedValue(dd1).toString();
            System.out.println(value);
    
            // 解析 ${}
            value = context.getEnvironment().resolvePlaceholders(value);
            System.out.println(value);
        }
    
        public class Bean1 {
            @Value("${JAVA_HOME}")
            private String home;
            @Value("18")
            private int age;
        }
    
        public class Bean2 {
            @Value("#{@bean3}") // SpringEL       #{SpEL}
            private Bean3 bean3;
        }
    
        @Component("bean3")
        public class Bean3 {
        }
    
        static class Bean4 {
            @Value("#{'hello, ' + '${JAVA_HOME}'}")
            private String value;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    收获💡
    1. ContextAnnotationAutowireCandidateResolver 作用之一,获取 @Value 的值
    2. 了解 ${ } 对应的解析器
    3. 了解 #{ } 对应的解析器
    4. TypeConvert 的一项体现

    47) @Autowired 装配底层

    演示 - @Autowired 装配过程
    代码参考
    package com.itheima.a47;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.ObjectFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.config.DependencyDescriptor;
    import org.springframework.beans.factory.support.DefaultListableBeanFactory;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
    import org.springframework.context.annotation.Lazy;
    import org.springframework.core.MethodParameter;
    import org.springframework.stereotype.Component;
    
    import java.lang.reflect.Method;
    import java.util.Optional;
    
    @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
            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 {
                        return beanFactory.doResolveDependency(dd4, "bean1", null, null);
                    }
                };
                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());
            /*
                学到了什么
                    1. Optional 及 ObjectFactory 对于内嵌类型的处理, 源码参考 ResolvableType
                    2. ObjectFactory 懒惰的思想
                    3. @Lazy 懒惰的思想
                下一节, 继续学习 doResolveDependency 内部处理
             */
        }
    
        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();
            }*/
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    package com.itheima.a47;
    
    import org.springframework.beans.factory.BeanFactoryUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.beans.factory.config.BeanDefinition;
    import org.springframework.beans.factory.config.BeanDefinitionHolder;
    import org.springframework.beans.factory.config.DependencyDescriptor;
    import org.springframework.beans.factory.support.DefaultListableBeanFactory;
    import org.springframework.beans.factory.support.RootBeanDefinition;
    import org.springframework.context.ConfigurableApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
    import org.springframework.stereotype.Component;
    
    import java.lang.reflect.Field;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    
    @SuppressWarnings("all")
    @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);
            /*
                学到了什么
                    1. 如何获取数组元素类型
                    2. Spring 如何获取泛型中的类型
                    3. 特殊对象的处理, 如 ApplicationContext, 并注意 Map 取值时的类型匹配问题 (另见  TestMap)
                    4. 谁来进行泛型匹配 (另见 TestGeneric)
                    5. 谁来处理 @Qualifier
                    6. 刚开始都只是按名字处理, 等候选者确定了, 才会创建实例
             */
        }
    
        private static void testQualifier(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
            DependencyDescriptor dd5 = new DependencyDescriptor(Target.class.getDeclaredField("service"), true);
            Class<?> type = dd5.getDependencyType();
            ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
            resolver.setBeanFactory(beanFactory);
            for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) {
                BeanDefinition bd = beanFactory.getMergedBeanDefinition(name);
                //                                                             @Qualifier("service2")
                if (resolver.isAutowireCandidate(new BeanDefinitionHolder(bd,name), dd5)) {
                    System.out.println(name);
                    System.out.println(dd5.resolveCandidate(name, type, beanFactory));
                }
            }
        }
        private static void testGeneric(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
            DependencyDescriptor dd4 = new DependencyDescriptor(Target.class.getDeclaredField("dao"), true);
            Class<?> type = dd4.getDependencyType();
            ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
            resolver.setBeanFactory(beanFactory);
            for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) {
                BeanDefinition bd = beanFactory.getMergedBeanDefinition(name);
                // 对比 BeanDefinition 与 DependencyDescriptor 的泛型是否匹配
                if (resolver.isAutowireCandidate(new BeanDefinitionHolder(bd,name), dd4)) {
                    System.out.println(name);
                    System.out.println(dd4.resolveCandidate(name, type, 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);
    //        dependencies.forEach((k, v) -> {
    //            System.out.println("key:" + k + " value: " + v);
    //        });
            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 Dao<T> {
    
        }
        @Component("dao1") static class Dao1 implements Dao<Student> {
        }
        @Component("dao2") static class Dao2 implements Dao<Teacher> {
        }
    
        static class Student {
    
        }
    
        static class Teacher {
    
        }
    
        interface Service {
    
        }
    
        @Component("service1")
        static class Service1 implements Service {
    
        }
    
        @Component("service2")
        static class Service2 implements Service {
    
        }
    
        @Component("service3")
        static class Service3 implements Service {
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    package com.itheima.a47;
    
    import org.springframework.beans.factory.BeanFactoryUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.config.BeanDefinition;
    import org.springframework.beans.factory.config.DependencyDescriptor;
    import org.springframework.beans.factory.support.BeanDefinitionBuilder;
    import org.springframework.beans.factory.support.DefaultListableBeanFactory;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.stereotype.Component;
    
    @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);
    
            /*
                学到了什么
                    1. @Primary 的处理, 其中 @Primary 会在 @Bean 解析或组件扫描时被解析 (另见 TestPrimary)
                    2. 最后的防线, 通过属性或参数名匹配
             */
        }
    
        private static void testDefault(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
            DependencyDescriptor dd = new DependencyDescriptor(Target2.class.getDeclaredField("service3"), false);
            Class<?> type = dd.getDependencyType();
            for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) {
                if(name.equals(dd.getDependencyName())) {
                    System.out.println(name);
                }
            }
        }
    
        private static void testPrimary(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
            DependencyDescriptor dd = new DependencyDescriptor(Target1.class.getDeclaredField("service"), false);
            Class<?> type = dd.getDependencyType();
            for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) {
                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("service2") static class Service2 implements Service {
    
        }
        @Component("service3") static class Service3 implements Service {
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    收获💡
    1. @Autowired 本质上是根据成员变量或方法参数的类型进行装配
    2. 如果待装配类型是 Optional,需要根据 Optional 泛型找到 bean,再封装为 Optional 对象装配
    3. 如果待装配的类型是 ObjectFactory,需要根据 ObjectFactory 泛型创建 ObjectFactory 对象装配
      • 此方法可以延迟 bean 的获取
    4. 如果待装配的成员变量或方法参数上用 @Lazy 标注,会创建代理对象装配
      • 此方法可以延迟真实 bean 的获取
      • 被装配的代理不作为 bean
    5. 如果待装配类型是数组,需要获取数组元素类型,根据此类型找到多个 bean 进行装配
    6. 如果待装配类型是 Collection 或其子接口,需要获取 Collection 泛型,根据此类型找到多个 bean
    7. 如果待装配类型是 ApplicationContext 等特殊类型
      • 会在 BeanFactory 的 resolvableDependencies 成员按类型查找装配
      • resolvableDependencies 是 map 集合,key 是特殊类型,value 是其对应对象
      • 不能直接根据 key 进行查找,而是用 isAssignableFrom 逐一尝试右边类型是否可以被赋值给左边的 key 类型
    8. 如果待装配类型有泛型参数
      • 需要利用 ContextAnnotationAutowireCandidateResolver 按泛型参数类型筛选
    9. 如果待装配类型有 @Qualifier
      • 需要利用 ContextAnnotationAutowireCandidateResolver 按注解提供的 bean 名称筛选
    10. 有 @Primary 标注的 @Component 或 @Bean 的处理
    11. 与成员变量名或方法参数名同名 bean 的处理

    48) 事件监听器

    演示 - 事件监听器
    代码参考
    package com.itheima.a48;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationEvent;
    import org.springframework.context.ApplicationEventPublisher;
    import org.springframework.context.ApplicationListener;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.event.ApplicationEventMulticaster;
    import org.springframework.stereotype.Component;
    
    // 事件解耦例子
    @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("发送邮件");
            }
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    package com.itheima.a48;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationEvent;
    import org.springframework.context.ApplicationEventPublisher;
    import org.springframework.context.ApplicationListener;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.event.EventListener;
    import org.springframework.context.event.SimpleApplicationEventMulticaster;
    import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
    import org.springframework.stereotype.Component;
    
    import java.util.concurrent.ThreadPoolExecutor;
    
    @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
            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;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    package com.itheima.a48;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.SmartInitializingSingleton;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationEvent;
    import org.springframework.context.ApplicationEventPublisher;
    import org.springframework.context.ConfigurableApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.stereotype.Component;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    import java.lang.reflect.Method;
    
    @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 () -> {
                for (String name : context.getBeanDefinitionNames()) {
                    Object bean = context.getBean(name);
                    for (Method method : bean.getClass().getMethods()) {
                        if (method.isAnnotationPresent(MyListener.class)) {
                            context.addApplicationListener((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();
                                    }
                                }
                            });
                        }
                    }
                }
            };
        }
    
        @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 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("发送邮件");
            }
        }
    
        @Retention(RetentionPolicy.RUNTIME)
        @Target(ElementType.METHOD)
        @interface MyListener {
        }
    
        static class MyEvent extends ApplicationEvent {
            public MyEvent(Object source) {
                super(source);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    收获💡

    事件监听器的两种方式

    1. 实现 ApplicationListener 接口
      • 根据接口泛型确定事件类型
    2. @EventListener 标注监听方法
      • 根据监听器方法参数确定事件类型
      • 解析时机:在 SmartInitializingSingleton(所有单例初始化完成后),解析每个单例 bean

    49) 事件发布器

    演示 - 事件发布器
    代码参考
    package com.itheima.a49;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationEvent;
    import org.springframework.context.ApplicationEventPublisher;
    import org.springframework.context.ApplicationListener;
    import org.springframework.context.ConfigurableApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.event.ApplicationEventMulticaster;
    import org.springframework.context.event.GenericApplicationListener;
    import org.springframework.core.ResolvableType;
    import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
    import org.springframework.stereotype.Component;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.function.Predicate;
    
    @Configuration
    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
            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<>();
    
                // 收集监听器
                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 封装为支持事件类型检查的 listener
                    GenericApplicationListener genericApplicationListener = new GenericApplicationListener() {
                        // 是否支持某事件类型                真实的事件类型
                        public boolean supportsEventType(ResolvableType eventType) {
                            return type.isAssignableFrom(eventType);
                        }
    
                        public void onApplicationEvent(ApplicationEvent event) {
                            executor.submit(() -> listener.onApplicationEvent(event));
                        }
                    };
    
                    listeners.add(genericApplicationListener);
                }
    
                // 发布事件
                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) {
    
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    package com.itheima.a49;
    
    import org.springframework.context.ApplicationEvent;
    import org.springframework.context.ApplicationListener;
    import org.springframework.context.PayloadApplicationEvent;
    import org.springframework.context.event.ApplicationEventMulticaster;
    import org.springframework.context.event.GenericApplicationListener;
    import org.springframework.context.support.GenericApplicationContext;
    import org.springframework.core.ResolvableType;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.function.Predicate;
    
    // 演示事件发布器实现要点
    public class TestEventPublisher {
        public static void main(String[] args) {
            GenericApplicationContext context = new GenericApplicationContext();
            context.registerBean("applicationEventMulticaster", MyApplicationEventMulticaster.class);
            context.refresh();
    
            context.publishEvent(new Object());
            context.publishEvent("aaaa");
            context.publishEvent(new Bean1());
        }
    
        interface Inter {
    
        }
    
        static class Bean1 implements Inter{
    
        }
    
        static class MyApplicationEventMulticaster implements ApplicationEventMulticaster {
    
            private List<ApplicationListener> listeners = new ArrayList<>();
    
            {
                listeners.add(new GenericApplicationListener() {
                    @Override
                    public void onApplicationEvent(ApplicationEvent event) {
                        if (event instanceof PayloadApplicationEvent payloadApplicationEvent) {
                            System.out.println(payloadApplicationEvent.getPayload());
                        }
                    }
    
                    @Override
                    public boolean supportsEventType(ResolvableType eventType) {
                        System.out.println(eventType);
                        // eventType --> PayloadApplicationEvent, PayloadApplicationEvent
                        return (Inter.class.isAssignableFrom(eventType.getGeneric().toClass()));
                    }
                });
            }
    
            @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) {
                multicastEvent(event, null);
            }
    
            @SuppressWarnings("all")
            @Override
            public void multicastEvent(ApplicationEvent event, ResolvableType eventType) {
                listeners.stream().filter(applicationListener -> {
                            if (eventType == null) {
                                return false;
                            }
                            if (applicationListener instanceof GenericApplicationListener genericApplicationListener) {
                                return genericApplicationListener.supportsEventType(eventType);
                            }
                            return false;
                        })
                        .forEach(applicationListener -> {
                            applicationListener.onApplicationEvent(event);
                        });
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    收获💡

    事件发布器模拟实现

    1. addApplicationListenerBean 负责收集容器中的监听器
      • 监听器会统一转换为 GenericApplicationListener 对象,以支持判断事件类型
    2. multicastEvent 遍历监听器集合,发布事件
      • 发布前先通过 GenericApplicationListener.supportsEventType 判断支持该事件类型才发事件
      • 可以利用线程池进行异步发事件优化
    3. 如果发送的事件对象不是 ApplicationEvent 类型,Spring 会把它包装为 PayloadApplicationEvent 并用泛型技术解析事件对象的原始类型
      • 视频中未讲解
  • 相关阅读:
    【9】c++11新特性 —>&&的特性
    论文Compiler Technologies in Deep Learning Co-Design: A Survey分享
    深度学习如何具有人类智能实现论述假说
    Linux安装Tomcat最新版
    Linux命令从入门到实战----文件目录类
    黑马VUE3视频笔记
    Avalonia项目打包安装包
    生物素偶联二硒化钨WSe2 (Biotin-WSe2)|羟基修饰PEG化二硒化钨WSe2纳米颗粒 (OH-WSe2)齐岳
    基于springboot的高校科研管理系统(源码+调试+LW)
    Python基础-连接Mysql数据库
  • 原文地址:https://blog.csdn.net/kuangzeng/article/details/132628145