SpringBoot系列二:SpringBoot自动配置原理

栏目: Java · 发布时间: 7年前

内容简介:上一章中我们提到主程序类的注解 @SpringBootApplication 注解,它其实是个组合注解,源码如下:最主要的还是三个配置 @SpringBootConfiguration、@EnableAutoConfigration、@ComponentScan 三个注解,下面我们来一一分析。查看@SpringBootConfiguration源码,其实它也就是@Configuration注解:

1 SpringBoot运作原理

上一章中我们提到主程序类的注解 @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
    )
    Class<?>[] exclude() default {};

    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    String[] excludeName() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackages"
    )
    String[] scanBasePackages() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackageClasses"
    )
    Class<?>[] scanBasePackageClasses() default {};
}

最主要的还是三个配置 @SpringBootConfiguration、@EnableAutoConfigration、@ComponentScan 三个注解,下面我们来一一分析。

1.1 @SpringBootConfiguration

查看@SpringBootConfiguration源码,其实它也就是@Configuration注解:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}

对于 @Configuration,我们并不陌生,它就是 JavaConfig 形式的 SpringIOC 容器的配置类,也是 SpringBoot 推荐使用配置形式,所以主程序类标注了 @SpringBootConfiguration 注解,其本身也就是一个配置类。更多有关 JavaConfig 形式的配置以及有关它和 XML 形式的配置的区别与联系,请参考后续有关 Spring 注解版相关文章。

1.2 @ComponentScan

@ComponentScan 注解在 Spring 的注解中也起到到相当重要的作用,它可以自定义 Spring 扫描的包,也就是它默认会扫描标注了 @Controller、@Service、@Component 以及 @Repository 注解的类,并实例化这些组件到 SpringIOC 容器中,它有个配置属性: basePackages,也就是指定扫描的包,如果不知道,它会默认扫描配置了该注解的类的包所在的路径(包括子包)。我们看 @SpringBootConfiguration 注解的源码中有段代码:

@AliasFor(
  annotation = ComponentScan.class,
  attribute = "basePackages"
)
String[] scanBasePackages() default {};

scanBasePackages 属性,指定到了 @ComponentScan 注解的 basePackages 属性,所有在 SpringBoot 中,我们同样可以通过 scanBasePackages 属性指定包扫描的路径(如部指定,会默认扫描主程序类所在的包路径以及子包下的类):

@SpringBootApplication(scanBasePackages = "com.seagetech.springbootdemo")

1.3 @EnableAutoConfigration

关于 SpringBoot 的运作原理,它的核心功能还是由 @EnableAutoConfigration 注解提供,所有把它放到最后来讲,我们来看下它的源码:

@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 {};
}

1.3.1 @AutoConfigurationPackage

这个注解的主要功能自动配置包,它会获取主程序类所在的包路径,并将包路径(包括子包)下的所有组件注册到 SpringIOC 容器中。

1.3.2 @Import({AutoConfigurationImportSelector.class})

@EnableAutoConfiguration 的关键功能也是这个 @Import 导入的配置功能,使用 SpringFactoriesLoader.loadFactoryNames 方法来扫描具有 META-INF/spring.factories 文件的jar包,我们看看在 spring-boot-autoconfigure-2.10.RELEASE.jar 包的 META-INF 下正好有个 spring.factories 文件:

SpringBoot系列二:SpringBoot自动配置原理

打开 spring.factories 文件,找到 org.springframework.boot.autoconfigure.EnableAutoConfiguration 指定的自动配置类:

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\

......
......

org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\

每一个 xxxAutoConfiguration 类都是容器中的一个组件,都加入到容器中,用它们来做自动配置。

2 自动配置分析

在上一节基础上,我们知道每一个自动配置类进行自动配置功能,下面我们以 HttpEncodingAutoConfiguration 为例来分析:

2.1 配置参数

@ConfigurationProperties(
    prefix = "spring.http"//①
)
public class HttpProperties {
    private boolean logRequestDetails;
    private final HttpProperties.Encoding encoding = new HttpProperties.Encoding();//②

    ......

    public static class Encoding {
        public static final Charset DEFAULT_CHARSET;
        private Charset charset;
        private Boolean force;
        private Boolean forceRequest;
        private Boolean forceResponse;
        private Map<Locale, Charset> mapping;

        public Encoding() {
            this.charset = DEFAULT_CHARSET;//②
        }
        ......
        static {
            DEFAULT_CHARSET = StandardCharsets.UTF_8;//②
        }
        ......
}

代码解析:

  1. 在 application.properties 文件中配置的时候指定前缀是 spring.http;
  2. 指定默认的编码方式是 UTF-8,如果需要修改,可使用 spring.http.encoding.charset=编码。

2.2 自动配置类

@Configuration//①
@EnableConfigurationProperties({HttpProperties.class})//②
@ConditionalOnWebApplication(
    type = Type.SERVLET
)//③
@ConditionalOnClass({CharacterEncodingFilter.class})//④
@ConditionalOnProperty(
    prefix = "spring.http.encoding",
    value = {"enabled"},
    matchIfMissing = true
)//⑤
public class HttpEncodingAutoConfiguration {
    private final Encoding properties;

    public HttpEncodingAutoConfiguration(HttpProperties properties) {
        this.properties = properties.getEncoding();
    }

    @Bean
    @ConditionalOnMissingBean
    public CharacterEncodingFilter characterEncodingFilter() {
        ......
    }
    .......
}

源码解析:

  1. 表示这是一个配置类,以前编写的配置文件一样,也可以给容器中添加组件。
  2. 启动指定类的 ConfigurationProperties 功能,将配置文件中对应的值和 HttpEncodingProperties 绑定起来;并把 HttpEncodingProperties 加入到 IOC 容器中;
  3. Spring 底层 @Conditional 注解(有关 @Conditional 注解的详解请参考后续 Spring 注解相关文章),根据不同的条件,如果满足指定的条件,整个配置类里面的配置就会生效,该注解是判断当前应用是否是web应用,如果是, HttpEncodingAutoConfiguration 配置类生效;
  4. 判断当前项目有没有这个类 CharacterEncodingFilter;SpringMVC 中进行乱码解决的过滤器,如果有则 HttpEncodingAutoConfiguration 配置生效;
  5. 判断 application.properties 配置文件中是否存在 spring.http.encoding.enabled,如果不存在,判断也是成立的,因为 matchIfMissing=true,即缺省时默认为 true。

根据当前不同的条件判断,决定 HttpEncodingAutoConfiguration 这个配置类是否生效?一但这个配置类生效;这个配置类就会给容器中添加各种组件,这些组件的属性是从对应的 HttpEncodingProperties 类中获取的,这些类里面的每一个属性又是和配置文件绑定的。

2.3@Conditional扩展注解

除了以上解析到的注解,SpringBoot 还为我们提供了更多的有关 @Conditional 的派生注解。它们的作用:必须是 @Conditional 指定的条件成立,才给容器中添加组件,配置配里面的所有内容才生效:

SpringBoot系列二:SpringBoot自动配置原理


以上所述就是小编给大家介绍的《SpringBoot系列二:SpringBoot自动配置原理》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

流畅的Python

流畅的Python

[巴西] Luciano Ramalho / 安道、吴珂 / 人民邮电出版社 / 2017-5-15 / 139元

【技术大咖推荐】 “很荣幸担任这本优秀图书的技术审校。这本书能帮助很多中级Python程序员掌握这门语言,我也从中学到了相当多的知识!”——Alex Martelli,Python软件基金会成员 “对于想要扩充知识的中级和高级Python程序员来说,这本书是充满了实用编程技巧的宝藏。”——Daniel Greenfeld和Audrey Roy Greenfeld,Two Scoops ......一起来看看 《流畅的Python》 这本书的介绍吧!

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具