• SpringBoot自动装配原理(简单易懂)


    1、什么是自动装配

    自动装配就是把别人(官方)写好的config配置类加载到spring容器,然后根据这个配置类生成一些项目需要的bean对象。
    (小声逼逼:就像我们自己在项目了写的config配置类一样的,只不过这个是别人写好的,你什么都不用管)

    2、自动装配的开关在哪里

    @SpringBootApplication
       |--@EnableAutoConfiguration
         |--@Import({AutoConfigurationImportSelector.class})
    
    • 1
    • 2
    • 3

    @SpringBootApplication注解里的@EnableAutoConfiguration@Import注解导入了一AutoConfigurationImportSelector.class类,这个类的selectImports方法会扫描我们类路径下的一个spring.factories文件(里面装的是很多官方写好的自动配置类的全限定名),然后返回这些类的名字。

    • selectImports方法如下:

      public String[] selectImports(AnnotationMetadata annotationMetadata) {
      if (!this.isEnabled(annotationMetadata)) {
      return NO_IMPORTS;
      } else {
      AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
      return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
      }
      }

    • spring.factories文件的位置如下:
      在这里插入图片描述

    • spring.factories文件的内容如下:
      在这里插入图片描述

    3、自动装配开始(以tomcat为例)

    前面的selectImports函数会拿到 spring.factories文件里的自动配置类,然后去解析这些配置类,这里以ServletWebServerFactoryAutoConfiguration为例
    在这里插入图片描述在这里插入图片描述这个类上面有很多条件注解,大致就是说当你的应用是web应用,符合spring MVC那一套,像什么Servlet啊等等,这个配置类才生效。其中这个配置类又用@Import注解导入了几个类如下:

    @Import({ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
     EmbeddedTomcat.class, 
     EmbeddedJetty.class, 
     EmbeddedUndertow.class})
    
    • 1
    • 2
    • 3
    • 4

    这几个看名字就知道是什么,就是一些web容器嘛,Tomcat、Jetty、Undertow。其实EmbeddedTomcat.classEmbeddedJetty.classEmbeddedUndertow.classServletWebServerFactoryConfiguration里的三个静态内部类。
    这里以EmbeddedTomcat.class这个内部类为例,代码如下:

     @ConditionalOnClass({Servlet.class, Tomcat.class, UpgradeProtocol.class})
        @ConditionalOnMissingBean(
            value = {ServletWebServerFactory.class},
            search = SearchStrategy.CURRENT
        )
        static class EmbeddedTomcat {
            EmbeddedTomcat() {
            }
    
            @Bean
            TomcatServletWebServerFactory tomcatServletWebServerFactory(ObjectProvider connectorCustomizers, ObjectProvider contextCustomizers, ObjectProvider> protocolHandlerCustomizers) {
                TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
                factory.getTomcatConnectorCustomizers().addAll((Collection)connectorCustomizers.orderedStream().collect(Collectors.toList()));
                factory.getTomcatContextCustomizers().addAll((Collection)contextCustomizers.orderedStream().collect(Collectors.toList()));
                factory.getTomcatProtocolHandlerCustomizers().addAll((Collection)protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));
                return factory;
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    注意:第一行的 @ConditionalOnClass({Servlet.class, Tomcat.class, UpgradeProtocol.class}),这个条件注解表示你的类路径下有tomcat的依赖,即导入了Tomcat的jar包才会生效,EmbeddedTomcat.classEmbeddedJetty.class也同理,但是只能有一个哈,导入了tomcat的jar包就不能导入其它的,不然会报错,当然了springboot默认tomcat,不需要我们导入。
    这里会返回一个TomcatServletWebServerFactory 类,点进去后,其代码如下:

    public class TomcatServletWebServerFactory 
    extends AbstractServletWebServerFactory 
    implements ConfigurableTomcatWebServerFactory, ResourceLoaderAware {
        其它代码不重要,哈哈。。。
    
    • 1
    • 2
    • 3
    • 4

    这里继承了一个AbstractServletWebServerFactory 类, --------------AbstractServletWebServerFactory 类又继承了--------------AbstractConfigurableWebServerFactory
    好,点击AbstractConfigurableWebServerFactory进去就可以看到我们熟悉的8080端口号了,如下:
    在这里插入图片描述

    3、结束语

    其实springboot的自动装配还是比较复杂的,大概可以概括为:在启动类的run方法传入启动类的class(方便后面获取其注解信息)。
    执行run方法,创建SpringApplication对象,并用LoadSpringFactories()方法将/META-INF/spring.factories文件里的k-v读入缓存(方便后面加载时使用)。
    然后继续run方法,在某处会获取传入的启动类的class,并解析上面的注解,当解析到@Import({AutoConfigurationImportSelector.class})时会将AutoConfigurationImportSelector加载进方法区,通过反射创建对象,调用其某一个方法,从缓存读取前面存储的k-v,并经过一系列的过滤、去重等,最后将需要的配置类加载,生成BD对象,创建Bean对象,放入spring容器。

    先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦

  • 相关阅读:
    记一次接口优化操作
    C语言关键字汇总
    黑磷和量子点结合分子印迹技术的荧光传感材料(BPS-QDs@MIP)
    433-C++基础语法(51-60)
    【高并发内存池】第一篇 项目简介及定长内存池
    Redis入门到通关之数据结构解析-RedisObject
    N位质数c++
    ASP.NET Core 使用redis
    最近5年133个Java面试问题列表
    vue3 使用语法糖,子父子间的传值以及方法调用
  • 原文地址:https://blog.csdn.net/m0_67390379/article/details/126115315