Springboot 系列(三)Spring Boot 自动配置

注意:本 Spring Boot 系列文章基于 Spring Boot 版本 v2.1.1.RELEASE 进行学习分析,版本不同可能会有细微差别。

前言

关于配置文件可以配置的内容,在 Spring Boot 官方网站已经提供了完整了配置示例和解释。

可以这么说,Spring Boot 的一大精髓就是自动配置,为开发省去了大量的配置时间,可以更快的融入业务逻辑的开发,那么自动配置是怎么实现的呢?

1. @SpringBootApplication

跟着 Spring Boot 的启动类的注解 @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 {

@EnableAutoConfiguration 开启自动配置。

@ComponentScan 开启注解扫描

SpringBootApplication 我们可以发现,这是一个简便的注解配置,它包含了自动配置,配置类,包扫描等一系列功能。

2. @EnableAutoConfiguration

继续跟踪,查看@EnableAutoConfiguration 源码,里面比较重要的是 @Import ,导入了一个翻译名为自动配置的选择器的类。这个类其实就是自动配置的加载选择器。

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

继续跟踪 AutoConfigurationImportSelector.class .在这个类有一个重要的方法 getCandidateConfigurations.用于加载 Spring Boot 配置的自动配置类。

getAutoConfigurationEntry 会筛选出有效的自动配置类。

protected AutoConfigurationEntry getAutoConfigurationEntry(
            AutoConfigurationMetadata autoConfigurationMetadata,
            AnnotationMetadata annotationMetadata) {
        if (!isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        }
        AnnotationAttributes attributes = getAttributes(annotationMetadata);
        List<String> configurations = getCandidateConfigurations(annotationMetadata,
                attributes);
        configurations = removeDuplicates(configurations);
        Set<String> exclusions = getExclusions(annotationMetadata, attributes);
        checkExcludedClasses(configurations, exclusions);
        configurations.removeAll(exclusions);
        configurations = filter(configurations, autoConfigurationMetadata);
        fireAutoConfigurationImportEvents(configurations, exclusions);
        return new AutoConfigurationEntry(configurations, exclusions);
    }   

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
            AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
                getSpringFactoriesLoaderFactoryClass(), 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;
    }

下图是 DEBUG 模式下筛选之后的结果,因为我只添加了 web 模块,所以只有 web 相关的自动配置。

3. xxxAutoConfiguration 与 xxxProperties

在上面的 debug 里,我们看到了成功加载的自动配置,目前只看到了配置类,却还没有发现自动配置值,随便选择一个 AutoConfiguration 查看源码。

这里选择了 ServletWebServerFactoryAutoConfiguration.

@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
//判断当前项目有没有这个类
//CharacterEncodingFilter;SpringMVC中进行乱码解决的过滤器;
@ConditionalOnClass(ServletRequest.class)
//Spring底层@Conditional注解(Spring注解版),根据不同的条件,如果
//满足指定的条件,整个配置类里面的配置就会生效; 判断当前应用是否是web应用,如果是,当前配置类生效
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
        ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
        ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
        ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {

需要注意的是 @EnableConfigurationProperties(ServerProperties.class).他的意思是启动指定类的

ConfigurationProperties功能;将配置文件中对应的值和 ServerProperties 绑定起来;并把

ServerProperties 加入到 IOC 容器中。

再来看一下 ServerProperties .

@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {

    /**
     * Server HTTP port.
     */
    private Integer port;

显而易见了,这里使用 ConfigurationProperties 绑定属性映射文件中的 server 开头的属性。结合默认配置

# 路径spring-boot-autoconfigure-2.1.1.RELEASE.jar
# /META-INF/spring-configuration-metadata.json

    {
      "name": "server.port",
      "type": "java.lang.Integer",
      "description": "Server HTTP port.",
      "sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties",
      "defaultValue": 8080
    }

达到了自动配置的目的。

4. 自动配置总结

  1. SpringBoot 启动的时候加载主配置类,开启了自动配置功能 @EnableAutoConfiguration 。
  2. @EnableAutoConfiguration 给容器导入META-INF/spring.factories 里定义的自动配置类。
  3. 筛选有效的自动配置类。
  4. 每一个自动配置类结合对应的 xxxProperties.java 读取配置文件进行自动配置功能 。

5. 配置类

通过自动配置,我们发现已经帮我们省去了大量的配置文件的编写,那么在自定义配置的时候,我们是不是需要编写XML呢?Spring boot 尽管可以使用 SpringApplicationXML 文件进行配置,但是我们通常会使用 @Configuration 类进行代替,这也是官方推荐的方式。

5.1 XML配置

定义 helloService Bean.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="helloService" class="net.codingme.boot.service.HelloService"></bean>

</beans>

引入配置。

@ImportResource(value = "classpath:spring-service.xml")
@SpringBootApplication
public class BootApplication {

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

5.2 注解配置

此种方式和上面的XML配置是等效的,也是官方推荐的方式。@Configuration 注解的类(要在扫描的包路径中)会被扫描到。

/**
 * <p>
 * 配置类,相当于传统Spring 开发中的 xml-> bean的配置
 *
 * @Author niujinpeng
 * @Date 2018/12/7 0:04
 */
@Configuration
public class ServiceConfig {

    /**
     * 默认添加到容器中的 ID 为方法名(helloService)
     *
     * @return
     */
    @Bean
    public HelloService helloService() {
        return new HelloService();
    }
}

6. 附录

@Conditional扩展注解 作用(判断是否满足当前指定条件)
@ConditionalOnJava 系统的java版本是否符合要求
@ConditionalOnBean 容器中存在指定Bean;
@ConditionalOnMissingBean 容器中不存在指定Bean;
@ConditionalOnExpression 满足SpEL表达式指定
@ConditionalOnClass 系统中有指定的类
@ConditionalOnMissingClass 系统中没有指定的类
@ConditionalOnSingleCandidate 容器中只有一个指定的Bean,或者这个Bean是首选Bean
@ConditionalOnProperty 系统中指定的属性是否有指定的值
@ConditionalOnResource 类路径下是否存在指定资源文件
@ConditionalOnWebApplication 当前是web环境
@ConditionalOnNotWebApplication 当前不是web环境
@ConditionalOnJndi JNDI存在指定项

文章代码已经上传到 GitHub Spring Boot 自动配置

<完>

本文原发于个人博客:https://www.codingme.net 转载请注明出处

原文地址:https://www.cnblogs.com/niumoo/p/10393547.html

时间: 2024-10-28 11:43:40

Springboot 系列(三)Spring Boot 自动配置的相关文章

Spring Boot自动配置原理(转)

第3章 Spring Boot自动配置原理 3.1 SpringBoot的核心组件模块 首先,我们来简单统计一下SpringBoot核心工程的源码java文件数量: 我们cd到spring-boot-autoconfigure工程根目录下.执行 $ tree | grep -c .java$ 模块 java文件数 spring-boot 551 spring-boot-actuator 423 spring-boot-autoconfigure 783 spring-boot-devtools

Spring Boot 自动配置之@Conditional的使用

Spring Boot自动配置的"魔法"是如何实现的? 转自-https://sylvanassun.github.io/2018/01/08/2018-01-08-spring_boot_auto_configure/ Spring Boot是Spring旗下众多的子项目之一,其理念是约定优于配置,它通过实现了自动配置(大多数用户平时习惯设置的配置作为默认配置)的功能来为用户快速构建出标准化的应用.Spring Boot的特点可以概述为如下几点: 内置了嵌入式的Tomcat.Jett

4、Spring Boot 自动配置原理

1.4 Spring Boot 自动配置原理 简介 spring boot自动配置功能可以根据不同情况来决定spring配置应该用哪个,不应该用哪个,举个例子: Spring的JdbcTemplate是不是在Classpath里面?如果是,并且DataSource也存在,就自动配置一个JdbcTemplate的Bean Thymeleaf是不是在Classpath里面?如果是,则自动配置Thymeleaf的模板解析器.视图解析器.模板引擎 那个这个是怎么实现的呢?原因就在于它利用了Spring的

Spring Boot自动配置类

http://docs.spring.io/spring-boot/docs/current/api/overview-summary.html http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#auto-configuration-classes 前提 1.一般来说,xxxAware接口,都提供了一个setXxx的方法,以便于其实现类将Xxx注入自身的xxx字段中,从而进行操作. 例如 Applicatio

Spring Boot自动配置实例

spring boot之所以能够自动配置bean,是通过基于条件来配置Bean的能力实现的. 常用的条件注解如下 @ConditionalOnBean:当容器里存在指定的Bean的条件下 @ConditionalOnClass:当前类路径下存在指定的类的条件下 @ConditionalOnExpression:基于SpEL表达式作为判断条件 @ConditionalOnJava:基于JVM版本作为判断条件 @ConditionalOnJndi:在JNDI存在的条件下查找指定的位置 @Condit

spring boot自动配置实现

自从用了spring boot,都忘记spring mvc中的xml配置是个什么东西了,再也回不去.为啥spring boot这么好用呢, 约定大于配置的设计初衷, 让我们只知道维护好application.properties(或application.yml)文件就可以了,我们在配置文件里可以设置数据源参数,可以设置服务端口,可以设置redis的地址等等.我们经常会看一些包含starter名字的jar包,如spring-boot-starter-data-redis,引入这些jar包,我们就

浅析spring boot自动配置原理

spring boot 源码刨析: 1.spring boot 启动类 @SpringBootApplication public class MgmtApplication extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { return builder.sources(MgmtAppli

Spring Boot自动配置源码解析(基于Spring Boot 2.0.2.RELEASE)

在Spring Boot官方介绍中,首一段话是这样的(如下图).我们可以大概了解到其所表达的含义:我们可以利用Spring Boot写很少的配置来创建一个非常方便的基于Spring整合第三方类库的单体企业级应用.相信使用过Spring Boot的人都知道,她在这方面从前到后的一系列整合.本篇文字将带你进入具体的实现细节. 首先我们写一段Spring Boot应用启动类的代码如下: 1 package com.springTest; 2 3 import org.springframework.b

spring boot 自动配置原理

1).spring boot启动的时候加载主配置类,开启了自动配置功能@EnableAutoConfiguration 2).通过@EnableAutoConfiguration中AutoConfigurationImportSelector给容器中导入了一系列的组件通过List<String> configurations = getCandidateConfigurations(annotationMetadata,attributes);获取候选的配置,下一步通过SpringFactor