• SpringBoot整合原理解析


    原理解析

    SpringBoot的启动过程

    阶段一:SpringApplication 构造

    1. 记录 BeanDefinition 源
    2. 推断应用类型
    3. 记录 ApplicationContext 初始化器
    4. 记录监听器
    5. 推断主启动类

    阶段二:执行 run 方法

    1. 得到 SpringApplicationRunListeners,名字取得不好,实际是事件发布器

      • 发布 application starting 事件1
    2. 封装启动 args

    3. 准备 Environment 添加命令行参数(*)

      (准备环境变量,和配置变量)

    4. ConfigurationPropertySources 处理(*)

      (添加一个处理参数格式的处理器)

      • 发布 application environment 已准备事件2
    5. 通过 EnvironmentPostProcessorApplicationListener 进行 env 后处理(*)

      • application.properties,由 StandardConfigDataLocationResolver 解析
      • spring.application.json
    6. 绑定 配置文件中的spring.main 到 SpringApplication 对象(*)

    7. 打印 banner(*)

    8. 创建容器

    9. 准备容器

      • 发布 application context 已初始化事件3
    10. 加载 bean 定义

    (有xml配置文件,包扫描,配置类3种方式加载bean定义)

    • 发布 application prepared 事件4
    1. refresh 容器

      (这一步就对应这spring调用bean后处理工厂和bean后处理器的方法)

      • 发布 application started 事件5
    2. 执行 runner

      • 发布 application ready 事件6

      • 这其中有异常,发布 application failed 事件7

    带 * 的有独立的示例

    演示 - 启动过程

    com.itheima.a39.A39_1 对应 SpringApplication 构造

    com.itheima.a39.A39_2 对应第1步,并演示 7 个事件

    com.itheima.a39.A39_3 对应第2、8到12步

    org.springframework.boot.Step3

    org.springframework.boot.Step4

    org.springframework.boot.Step5

    org.springframework.boot.Step6

    org.springframework.boot.Step7

    收获💡

    1. SpringApplication 构造方法中所做的操作

      • 可以有多种源用来加载 bean 定义
      • 应用类型推断
      • 添加容器初始化器
      • 添加监听器
      • 演示主类推断
    2. 如何读取 spring.factories 中的配置

    3. 从配置中获取重要的事件发布器:SpringApplicationRunListeners

    4. 容器的创建、初始化器增强、加载 bean 定义等

    5. CommandLineRunner、ApplicationRunner 的作用

      (CommandLineRunner执行的是原始的参数,ApplicationRunner执行的是经过处理的参数)

    6. 环境对象

      1. 命令行 PropertySource
      2. ConfigurationPropertySources 规范环境键名称
      3. EnvironmentPostProcessor 后处理增强
        • 由 EventPublishingRunListener 通过监听事件2️⃣来调用
      4. 绑定 spring.main 前缀的 key value 至 SpringApplication
    7. Banner

    内嵌容器

    springboot为我们集成了tomcat服务器,下图是一个运行在tomcat上jar包的文件结构

    Server
    └───Service
        ├───Connector (协议, 端口)
        └───Engine
            └───Host(虚拟主机 localhost)
                ├───Context1 (应用1, 可以设置虚拟路径, / 即 url 起始路径; 项目磁盘路径, 即 docBase )
                │   │   index.html
                │   └───WEB-INF
                │       │   web.xml (servlet, filter, listener) 3.0
                │       ├───classes (servlet, controller, service ...)
                │       ├───jsp
                │       └───lib (第三方 jar 包)
                └───Context2 (应用2)
                    │   index.html
                    └───WEB-INF
                            web.xml
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    SpringBoot内嵌tomcat关键代码演示

        public static void main(String[] args) throws LifecycleException, IOException {
            // 1.创建 Tomcat 对象
            Tomcat tomcat = new Tomcat();
            tomcat.setBaseDir("tomcat");
    
            // 2.创建项目文件夹, 即 docBase 文件夹
            File docBase = Files.createTempDirectory("boot.").toFile();
            docBase.deleteOnExit();
    
            // 3.创建 Tomcat 项目, 在 Tomcat 中称为 Context
            Context context = tomcat.addContext("", docBase.getAbsolutePath());
    
            WebApplicationContext springContext = getApplicationContext();
    
            // 4.编程添加 Servlet
            context.addServletContainerInitializer(new ServletContainerInitializer() {
                @Override
                public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
                    HelloServlet helloServlet = new HelloServlet();
                    servletContext.addServlet("aaa", helloServlet).addMapping("/hello");
    
                    DispatcherServlet dispatcherServlet = springContext.getBean(DispatcherServlet.class);
                    servletContext.addServlet("dispatcherServlet", dispatcherServlet).addMapping("/");
                }
            }, Collections.emptySet());
    
            // 5.启动 Tomcat
            tomcat.start();
    
            // 6.创建连接器, 设置监听端口
            Connector connector = new Connector(new Http11Nio2Protocol());
            connector.setPort(8080);
            tomcat.setConnector(connector);
        }
    
    • 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

    这个是基于javaEE的servlet

    public class HelloServlet extends HttpServlet {
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.setContentType("text/html;charset=utf-8");
            resp.getWriter().print("""
                    

    hello

    """
    ); } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    那么我们需要在编程添加 Servlet这一步添加基于MVC的Controller

    关键代码

    WebApplicationContext springContext = getApplicationContext();
    
    // 4.编程添加 Servlet
    context.addServletContainerInitializer(new ServletContainerInitializer() {
        @Override
        public void onStartup(Set> c, ServletContext ctx) throws ServletException {
            // ⬇️通过 ServletRegistrationBean 添加 DispatcherServlet 等
            for (ServletRegistrationBean registrationBean : 
                 springContext.getBeansOfType(ServletRegistrationBean.class).values()) {
                registrationBean.onStartup(ctx);
            }
        }
    }, Collections.emptySet());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    除此之外SpringBoot还内嵌了数据库,和内嵌缓存数据库

    自动配置

    SpringBoot还有一个重要的特性就是帮助我们自动配置了很多经常用到的库。

    如何实现的,这是还原了部分源代码

        @Configuration // 本项目的配置类
        @Import(MyImportSelector.class)
        static class Config {
            //自己定义和第三方定义,自己定义的后加载,后加载的会覆盖先加载的
            @Bean
            public Bean1 bean1() {
                return new Bean1("本项目");
            }
        }
    
        static class MyImportSelector implements DeferredImportSelector {
            @Override
            public String[] selectImports(AnnotationMetadata importingClassMetadata) {
                List<String> names = SpringFactoriesLoader.loadFactoryNames(MyImportSelector.class, null);
                return names.toArray(new String[0]);
            }
        }
    
        @Configuration // 第三方的配置类
        static class AutoConfiguration1 {
            @Bean
            @ConditionalOnMissingBean
            public Bean1 bean1() {
                return new 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

    这里有一个非常重要的方法SpringFactoriesLoader.loadFactoryNames我们尝试打印一下他的返回值names

    for (String name : names) {
        System.out.println("names返回值" + name);
    }
    
    • 1
    • 2
    • 3

    names返回值com.example.a35.A41_1.AutoConfiguration1
    names返回值com.example.a35.A41_1.AutoConfiguration2

    他的结果是这个,这是因为

    image-20220805160656195

    image-20220805160712476

    在META-INF中有一个spring.factories的文件,他里面定义了需要加载的配置类而SpringFactoriesLoader.loadFactoryNames就是获取所有配置类并且进行自动配置.

    image-20220805160901587

    我们可以发现SpringBoot的starter包里面会有spring.factories自动配置的文件

    下面我们来介绍几种常用的库的自动配置

    AopAutoConfiguration

    Spring Boot 是利用了自动配置类来简化了 aop 相关配置

    • AOP 自动配置类为 org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
    • 可以通过 spring.aop.auto=false 禁用 aop 自动配置
    • AOP 自动配置的本质是通过 @EnableAspectJAutoProxy 来开启了自动代理,如果在引导类上自己添加了 @EnableAspectJAutoProxy 那么以自己添加的为准
    • @EnableAspectJAutoProxy 的本质是向容器中添加了 AnnotationAwareAspectJAutoProxyCreator 这个 bean 后处理器,它能够找到容器中所有切面,并为匹配切点的目标类创建代理,创建代理的工作一般是在 bean 的初始化阶段完成的

    DataSourceAutoConfiguration

    Spring Boot 管理关系型数据库的自动配置类

    • 对应的自动配置类为:org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
    • @EnableConfigurationProperties({DataSourceProperties.class}) ,通过这个来配置添加配置参数如url,username,password

    简单说明一下,Spring Boot 支持两大类数据源:

    • EmbeddedDatabase - 内嵌数据库连接池(测试或者是小项目使用)
    • PooledDataSource - 非内嵌数据库连接池

    PooledDataSource 又支持如下数据源

    • hikari 提供的 HikariDataSource
    • tomcat-jdbc 提供的 DataSource
    • dbcp2 提供的 BasicDataSource
    • oracle 提供的 PoolDataSourceImpl

    MybatisAutoConfiguration

    • MyBatis 自动配置类为 org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
    • 它主要配置了两个 bean
      • SqlSessionFactory - MyBatis 核心对象,用来创建 SqlSession
      • SqlSessionTemplate - SqlSession 的实现,此实现会与当前线程绑定
      • 用 ImportBeanDefinitionRegistrar 的方式扫描所有标注了 @Mapper 注解的接口
      • 用 AutoConfigurationPackages 来确定扫描的包
    • 还有一个相关的 bean:MybatisProperties,它会读取配置文件中带 mybatis. 前缀的配置项进行定制配置

    @MapperScan 注解的作用与 MybatisAutoConfiguration 类似,会注册 MapperScannerConfigurer 有如下区别

    • @MapperScan 扫描具体包(当然也可以配置关注哪个注解)
    • @MapperScan 如果不指定扫描具体包,则会把引导类范围内,所有接口当做 Mapper 接口
    • MybatisAutoConfiguration 关注的是所有标注 @Mapper 注解的接口,会忽略掉非 @Mapper 标注的接口

    这里有同学有疑问,之前介绍的都是将具体类交给 Spring 管理,怎么到了 MyBatis 这儿,接口就可以被管理呢?

    • 其实并非将接口交给 Spring 管理,而是每个接口会对应一个 MapperFactoryBean,是后者被 Spring 所管理,接口只是作为 MapperFactoryBean 的一个属性来配置

    TransactionAutoConfiguration

    • 事务自动配置类有两个:

      • org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration
      • org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration
    • 前者配置了 DataSourceTransactionManager 用来执行事务的提交、回滚操作

    • 后者功能上对标 @EnableTransactionManagement,包含以下三个 bean

      • BeanFactoryTransactionAttributeSourceAdvisor 事务切面类,包含通知和切点
      • TransactionInterceptor 事务通知类,由它在目标方法调用前后加入事务操作
      • AnnotationTransactionAttributeSource 会解析 @Transactional 及事务属性,也包含了切点功能
    • 如果自己配置了 DataSourceTransactionManager 或是在引导类加了 @EnableTransactionManagement,则以自己配置的为准

    自动装配

    前面我们介绍了很多其他第三方的自动装配的原理,如果我们写的库需要自动装配需要怎么做

    在SpringBoot中,需要在META-INF的spring.factories中添加

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    com.example.a35.A41_2.AutoConfiguration1,\
    com.example.a35.A41_2.AutoConfiguration2
    
    • 1
    • 2
    • 3

    他起到的作用和上面MyImportSelector一样,不过SpringBoot会自动import

    EnableAutoConfiguration

    public class A41_2 {
    
        public static void main(String[] args) throws IOException {
            AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext();
            StandardEnvironment env = new StandardEnvironment();
            env.getPropertySources().addLast(new SimpleCommandLinePropertySource(
                    "--spring.datasource.url=jdbc:mysql://localhost:3306/eesy",
                    "--spring.datasource.username=root",
                    "--spring.datasource.password=123456"
            ));
            context.setEnvironment(env);
            context.registerBean("config", Config.class);
            context.refresh();
    
            for (String name : context.getBeanDefinitionNames()) {
                String resourceDescription = context.getBeanDefinition(name).getResourceDescription();
                if (resourceDescription != null)
                    System.out.println(name + " 来源:" + resourceDescription);
            }
            context.close();
        }
    
        @Configuration // 本项目的配置类
        @EnableAutoConfiguration
        static class Config {
            @Bean
            public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
                return new TomcatServletWebServerFactory();
            }
        }
    
    
        @Configuration // 第三方的配置类
        static class AutoConfiguration1 {
            @Bean
            public Bean1 bean1() {
                return new Bean1();
            }
        }
    
        @Configuration // 第三方的配置类
        static class AutoConfiguration2 {
            @Bean
            public Bean2 bean2() {
                return new Bean2();
            }
        }
    
        static class Bean1 {
    
        }
        static class 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

    条件装配

    在应用的过程中我们往往需要进行条件装配,比如在web场景下如果导入的是tomcat依赖我们就不需要Jetty和Undertow,下面代码复刻了功能

        static class MyCondition implements Condition { // 存在 Druid 依赖
            @Override
            public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
                Map attributes = metadata.getAnnotationAttributes(ConditionalOnClass.class.getName());
                String className = attributes.get("className").toString();
                boolean exists = (boolean) attributes.get("exists");
                boolean present = ClassUtils.isPresent(className, null);
                return exists ? present : !present;
            }
        }
    
        @Retention(RetentionPolicy.RUNTIME)
        @Target({ElementType.METHOD, ElementType.TYPE})
        @Conditional(MyCondition.class)
        @interface ConditionalOnClass {
            boolean exists(); // true 判断存在 false 判断不存在
    
            String className(); // 要判断的类名
        }
    
        @Configuration // 第三方的配置类
        @ConditionalOnClass(className = "com.alibaba.druid.pool.DruidDataSource", exists = false)
        static class AutoConfiguration1 {
            @Bean
            public Bean1 bean1() {
                return new 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

    @Value注入底层

    概况:Spring中Environment中存放可能用到的参数context会对他进行解析比如解析 ${}

        public static void main(String[] args) throws Exception {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A39.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"));
        }
        
        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;
        }
    
    • 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

    同时@Value还可以导入Bean

    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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    public class Bean2 {
        @Value("#{@bean3}") // SpringEL       #{SpEL}
        private Bean3 bean3;
    }
    
    • 1
    • 2
    • 3
    • 4

    @Autowired导入底层

    DependencyDescriptor在@Autowired中这个类比较关键,他负责描述了,注入bean的依赖

    成员变量注入

    DependencyDescriptor dd1 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean2"), false);
    Object bean1 = beanFactory.doResolveDependency(dd1, "bean1", null, null);
    
    • 1
    • 2
    @Autowired
    private Bean2 bean2;
    
    • 1
    • 2

    根据参数类型注入

    Method setBean2 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);
    DependencyDescriptor dd2 = new DependencyDescriptor(new MethodParameter(setBean2, 0), false);
    Object bean2 = beanFactory.doResolveDependency(dd2, "bean2", null, null);
    
    • 1
    • 2
    • 3
    @Autowired
    public void setBean2(Bean2 bean2) {
        this.bean2 = bean2;
    }
    
    • 1
    • 2
    • 3
    • 4

    包装为 Optional

    DependencyDescriptor dd3 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean3"), false);
    dd3.increaseNestingLevel();
    Object bean3 = beanFactory.doResolveDependency(dd3, "bean3", null, null);
    
    • 1
    • 2
    • 3

    increaseNestingLevel只有我们调用了这个方法之后会获取到Bean2

    @Autowired
    private Optional<Bean2> bean3;
    
    • 1
    • 2

    包装为 ObjectProvider,ObjectFactory

    DependencyDescriptor dd4 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean4"), false);
    if (dd4.getDependencyType() == ObjectFactory.class) {
        dd4.increaseNestingLevel();
        Object bean4 = beanFactory.doResolveDependency(dd4, "bean1", null, null);
        System.out.println(bean4);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    @Autowired
    private ObjectFactory<Bean2> bean4;
    
    • 1
    • 2

    数组类型

    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);
            }
            beanFactory.getTypeConverter().convertIfNecessary(beans, dd1.getDependencyType());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    @Autowired
    private Service[] serviceArray;
    
    • 1
    • 2

    list类型

    与数组类型类似

    DependencyDescriptor dd2 = new DependencyDescriptor(Target.class.getDeclaredField("serviceList"), true);
    if (dd2.getDependencyType() == List.class) {
        Class<?> resolve = dd2.getResolvableType().getGeneric().resolve();
        System.out.println(resolve);
        String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, resolve);
        List<Object> beanList = new ArrayList<>();
        for (String name : names) {
            System.out.println(name);
            Object o = dd2.resolveCandidate(name, resolve, beanFactory);
            beanList.add(o);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    @Autowired
    private List<Service> serviceList;
    
    • 1
    • 2

    ApplicationContext

    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()) {
        dependencies.get(ConfigurableApplicationContext.class);
        if (entry.getKey().isAssignableFrom(ConfigurableApplicationContext.class)) {
            System.out.println(entry.getValue());
            break;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    @Autowired
    private ConfigurableApplicationContext applicationContext;
    
    • 1
    • 2

    泛型

    DependencyDescriptor dd4 = new DependencyDescriptor(Target.class.getDeclaredField("dao"), true);
    ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
    Class<?> type = dd4.getDependencyType();
    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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    interface Dao<T> {
    }
    @Component("dao1")
    static class Dao1 implements Dao<Student> {
    }
    
    @Component("dao2")
    static class Dao2 implements Dao<Teacher> {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    @Qualifier

    根据名字注入

    DependencyDescriptor dd5 = new DependencyDescriptor(Target.class.getDeclaredField("service"), true);
    Class<?> dependencyType = dd5.getDependencyType();
    ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
    for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, dependencyType)) {
        BeanDefinition bd = beanFactory.getMergedBeanDefinition(name);
        if (resolver.isAutowireCandidate(new BeanDefinitionHolder(bd, name), dd5)) {
            System.out.println(name);
            System.out.println(dd5.resolveCandidate(name, dependencyType, beanFactory));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    @Autowired
    @Qualifier("service2")
    private Service service;
    
    • 1
    • 2
    • 3
    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

    @Primary

    优先查找

    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")
    @Primary
    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
    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);
                System.out.println(dd.resolveCandidate(name, type, beanFactory));
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    Default

    默认根据名字进行查找

    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);
                System.out.println(dd.resolveCandidate(name, type, beanFactory));
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    发布监听

    当我们的系统需要异步,除了使用mq中间件以为我们还可以通过,使用springboot事件监听器和发布器来完成,下面就是一个使用它的案例,不过他的缺点就是对于分布式的支持并不是很好

    @Configuration
    public class A41_1 {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A41_1.class);
            context.getBean(MyService.class).doBusiness();
            context.close();
        }
    
        static class MyEvent extends ApplicationEvent{
            public MyEvent(Object source) {
                super(source);
            }
        }
    
        @Component
        @Slf4j
        static class MyService {
    
            @Autowired
            private ApplicationEventPublisher publisher;
    
            public void doBusiness(){
                log.info("主线业务");
                publisher.publishEvent(new MyEvent("myService.doBusiness"));
    //            log.info("发送短信");
    //            log.info("发送邮件");
            }
        }
    
        @Component
        @Slf4j
        static class smsApplicationListener implements ApplicationListener<MyEvent> {
            @Override
            public void onApplicationEvent(MyEvent event) {
                log.info("发送短信");
            }
        }
    
        @Component
        @Slf4j
        static class emailApplicationListener implements ApplicationListener<MyEvent> {
            @Override
            public void onApplicationEvent(MyEvent event) {
                log.info("发送邮件");
            }
        }
    }
    
    • 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

    事件监听器

    自定义一个监听器

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    @interface MyListener {
    }
    
    • 1
    • 2
    • 3
    • 4

    配置一个SmartInitializingSingleton,使他对于listener进行解析

    @Bean
    public SmartInitializingSingleton smartInitializingSingleton(ConfigurableApplicationContext context) {
        return () -> {
            //获取任意类型的bean加了MyListener注解解析他
            for (String name : context.getBeanDefinitionNames()) {
                Object bean = context.getBean(name);
                for (Method method : bean.getClass().getMethods()) {
                    if (method.isAnnotationPresent(MyListener.class)) {
                        ApplicationListener<ApplicationEvent> listener = event -> {
                            //监听器方法需要的类型
                            Class<?> eventType = method.getParameterTypes()[0];
                            //筛选事件类型
                            if(eventType.isAssignableFrom(event.getClass())){
                                try {
                                    method.invoke(bean, event);
                                } catch (IllegalAccessException | InvocationTargetException e) {
                                    throw new RuntimeException(e);
                                }
                            }
                        };
                        //加入到context
                        context.addApplicationListener(listener);
                    }
                }
            }
        };
    }
    
    • 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

    事件发布器

    @Bean
    public ApplicationEventMulticaster applicationEventMulticaster(ConfigurableApplicationContext applicationContext, ThreadPoolTaskExecutor executor) {
        return new AbstractApplicationEventMulticaster() {
            private List<GenericApplicationListener> listeners = new ArrayList<>();
    
            @Override
            public void addApplicationListenerBean(String listenerBeanName) {
                log.info(listenerBeanName);
                ApplicationListener bean = applicationContext.getBean(listenerBeanName, ApplicationListener.class);
                //获取事件类型
                ResolvableType type = ResolvableType.forClass(bean.getClass()).getInterfaces()[0].getGeneric();
                log.info(String.valueOf(type));
    
                //将原始的listener封装为支持类型检查的listener
                GenericApplicationListener genericApplicationListener = new GenericApplicationListener() {
                    @Override
                    public void onApplicationEvent(ApplicationEvent event) {
                        executor.submit(()-> bean.onApplicationEvent(event));
                    }
    
                    //是否支持事件类型
                    @Override
                    public boolean supportsEventType(ResolvableType eventType) {
                        return type.isAssignableFrom(eventType);
                    }
                };
                listeners.add(genericApplicationListener);
            }
    
            @Override
            public void multicastEvent(ApplicationEvent event, ResolvableType eventType) {
                listeners.forEach(i -> {
                    if (i.supportsEventType(ResolvableType.forClass(event.getClass()))) {
                        i.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

    添加一个线程池

    @Bean
    public ThreadPoolTaskExecutor executor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(3);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(100);
        return executor;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    浏览器插件有什么作用,怎么安装浏览器扩展插件
    ECMASript 6 新特性
    UniApp百度人脸识别插件YL-FaceDetect
    shell语法(一)
    搭建一个干净整洁的vue前端开发环境
    TS基础篇
    音视频开发31 FFmpeg 编码- avcodec_find_encoder和avcodec_find_encoder_by_name
    8通道1:2或2:1双向多路复用器/多路解复用器,GRANDMICRO有容微的ASW3810可以代完美替
    博客迁移说明
    goioc:一个使用 Go 写的简易的 ioc 框架
  • 原文地址:https://blog.csdn.net/weixin_53227758/article/details/126288407