美文网首页Spring
SpringBoot起步依赖,自动装配,原理分析

SpringBoot起步依赖,自动装配,原理分析

作者: striveSmile | 来源:发表于2018-12-09 21:46 被阅读0次

    一、分析spring-boot-starter-parent

    按住Ctrl点击pom.xml中的spring-boot-starter-parent,跳转到了spring-boot-starter-parent的pom.xml,xml配
    置如下(只摘抄了部分重点配置):

        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.0.3.RELEASE</version>
            <relativePath>../../spring-boot-dependencies</relativePath>
        </parent>
    

    这里他还有个爸爸也就是SpringBoot的爷爷

    按住Ctrl点击pom.xml中的spring-boot-starter-dependencies,跳转到了spring-boot-starter-dependencies的
    pom.xml,xml配置如下(只摘抄了部分重点配置):

     <dependency>
                    <groupId>org.yaml</groupId>
                    <artifactId>snakeyaml</artifactId>
                    <version>${snakeyaml.version}</version>
                </dependency>
                <dependency>
                    <groupId>redis.clients</groupId>
                    <artifactId>jedis</artifactId>
                    <version>${jedis.version}</version>
                </dependency>
            </dependencies>
        </dependencyManagement>
        <build>
            <pluginManagement>
                <plugins>
                    <plugin>
                        <groupId>org.jetbrains.kotlin</groupId>
                        <artifactId>kotlin-maven-plugin</artifactId>
                        <version>${kotlin.version}</version>
                    </plugin>
                    <plugin>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-maven-plugin</artifactId>
                        <version>2.0.3.RELEASE</version>
                    </plugin>
    

    从上面的spring-boot-starter-dependencies的pom.xml中我们可以发现,一部分坐标的版本、依赖管理、插件管理已经定义好,所以我们的SpringBoot工程继承spring-boot-starter-parent后已经具备版本锁定等配置了。所以起步依赖的作用就是进行依赖的传递

    二、分析spring-boot-starter-web

    按住Ctrl点击pom.xml中的spring-boot-starter-web,跳转到了spring-boot-starter-web的pom.xml,xml配置如
    下(只摘抄了部分重点配置):

      <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starters</artifactId>
        <version>2.0.3.RELEASE</version>
      </parent>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-tomcat</artifactId>
          <version>2.0.3.RELEASE</version>
          <scope>compile</scope>
        </dependency>
        <dependency>
          <groupId>org.hibernate.validator</groupId>
          <artifactId>hibernate-validator</artifactId>
          <version>6.0.10.Final</version>
          <scope>compile</scope>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-web</artifactId>
          <version>5.0.7.RELEASE</version>
          <scope>compile</scope>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-webmvc</artifactId>
          <version>5.0.7.RELEASE</version>
          <scope>compile</scope>
        </dependency>
      </dependencies>
    

    从上面的spring-boot-starter-web的pom.xml中我们可以发现,spring-boot-starter-web就是将web开发要使用的spring-web、spring-webmvc等坐标进行了“打包”,这样我们的工程只要引入spring-boot-starter-web起步依赖的坐标就可以进行web开发了,同样体现了依赖传递的作

    三、自动配置原理解析

    按住Ctrl点击查看启动类MySpringBootApplication上的注解@SpringBootApplication

    @SpringBootApplication
    public class DemoApplication {
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    }
    

    注解@SpringBootApplication的源码

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan(
        excludeFilters = {@Filter(
        type = FilterType.CUSTOM,
        classes = {TypeExcludeFilter.class}
    ), @Filter(
        type = FilterType.CUSTOM,
        classes = {AutoConfigurationExcludeFilter.class}
    )}
    )
    public @interface SpringBootApplication {
        @AliasFor(
            annotation = EnableAutoConfiguration.class
        )
    

    其中,
    @SpringBootConfiguration:等同与@Configuration,既标注该类是Spring的一个配置类
    @EnableAutoConfiguration:SpringBoot自动配置功能开启
    @ComponentScan:组件扫描配置 约定 当前所在的包及子包下的都会被扫描到

    详解@EnableAutoConfiguration

    按住Ctrl点击查看注解@EnableAutoConfiguration

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage
    @Import({AutoConfigurationImportSelector.class})
    public @interface EnableAutoConfiguration {
        String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    
        Class<?>[] exclude() default {};
    
        String[] excludeName() default {};
    

    其中,@Import(AutoConfigurationImportSelector.class) 导入了AutoConfigurationImportSelector类
    按住Ctrl点击查看AutoConfigurationImportSelector源码

    
    public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
        private static final String[] NO_IMPORTS = new String[0];
        private static final Log logger = LogFactory.getLog(AutoConfigurationImportSelector.class);
        private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";
        private ConfigurableListableBeanFactory beanFactory;
        private Environment environment;
        private ClassLoader beanClassLoader;
        private ResourceLoader resourceLoader;
    
        public AutoConfigurationImportSelector() {
        }
    
    
        protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
            List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
            Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
            return configurations;
        }
    

    其中,SpringFactoriesLoader.loadFactoryNames 方法的作用就是从META-INF/spring.factories文件中读取指定类对应的类名称列表

    image.png
    spring.factories 文件中有关自动配置的配置信息如下:
    image.png
    上面配置文件存在大量的以Configuration为结尾的类名称,这些类就是存有自动配置信息的类,而
    SpringApplication在获取这些类名后再加载
    我们以ServletWebServerFactoryAutoConfiguration为例来分析源码
    image.png
    @Configuration
    @AutoConfigureOrder(-2147483648)
    @ConditionalOnClass({ServletRequest.class})
    @ConditionalOnWebApplication(
        type = Type.SERVLET
    )
    @EnableConfigurationProperties({ServerProperties.class})
    @Import({ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, EmbeddedTomcat.class, EmbeddedJetty.class, EmbeddedUndertow.class})
    public class ServletWebServerFactoryAutoConfiguration {
        public ServletWebServerFactoryAutoConfiguration() {
        }
    
        @Bean
        public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) {
            return new ServletWebServerFactoryCustomizer(serverProperties);
        }
    

    其中,
    @EnableConfigurationProperties(ServerProperties.class) 代表加载ServerProperties服务器配置属性类
    进入ServerProperties.class源码如下:

    @ConfigurationProperties(
        prefix = "server",
        ignoreUnknownFields = true
    )
    public class ServerProperties {
        private Integer port;
        private InetAddress address;
        @NestedConfigurationProperty
        private final ErrorProperties error = new ErrorProperties();
        private Boolean useForwardHeaders;
        private String serverHeader;
        private int maxHttpHeaderSize = 0;
        private Duration connectionTimeout;
        @NestedConfigurationProperty
        private Ssl ssl;
        @NestedConfigurationProperty
        private final Compression compression = new Compression();
        @NestedConfigurationProperty
        private final Http2 http2 = new Http2();
        private final ServerProperties.Servlet servlet = new ServerProperties.Servlet();
        private final ServerProperties.Tomcat tomcat = new ServerProperties.Tomcat();
        private final ServerProperties.Jetty jetty = new ServerProperties.Jetty();
        private final ServerProperties.Undertow undertow = new ServerProperties.Undertow();
    

    其中,
    prefix = "server" 表示SpringBoot配置文件中的前缀,SpringBoot会将配置文件中以server开始的属性映射到该类
    的字段中。映射关系如下:


    image.png

    相关文章

      网友评论

        本文标题:SpringBoot起步依赖,自动装配,原理分析

        本文链接:https://www.haomeiwen.com/subject/snathqtx.html