小白都能听懂的spring boot自动化配置原理

简介: spring boot最核心的特性就是他的自动化配置特性,极大的减少了构建一个spring web工程的工作量。那么你知道spring boot自动化配置的原理吗?

先直接自定义一个user-spring-boot-starter组件,感受下自动化配置的魅力。


构建user-spring-boot-starter


pom依赖

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.laowan</groupId>
    <artifactId>user-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>user-spring-boot-starter</name>
    <description>user-spring-boot-starter</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>


添加配置属性


spring.user.enabled=false
spring.user.name=laowan


创建UserPorperties属性类使用配置属性


@Data
@ConfigurationProperties("spring.user")
public class UserPorperties {
    private String name;
}


利用属性类UserPorperties构建UserClient对象

public class UserClient {
    private UserPorperties userPorperties;
    public UserClient(){
    }
    public UserClient(UserPorperties userPorperties){
          this.userPorperties = userPorperties;
    }
    public String getName(){
        return userPorperties.getName();
    }
}


核心:创建UserAutoConfigure自动化配置类


@Configuration
@EnableConfigurationProperties(UserPorperties.class)
public class UserAutoConfigure {
    @Bean
    @ConditionalOnProperty(prefix = "spring.user",value ="enabled",havingValue = "true")
    public UserClient userClient(UserPorperties userPorperties){
        return new UserClient(userPorperties);
    }
}


说明:

@ConfigurationProperties(“spring.user”)

读取以spring.user为前缀的属性文件,配置实体类


@EnableConfigurationProperties(UserPorperties.class)

将使用了@ConfigurationProperties 注解的类注入到spring容器中。

如果一个配置类只配置@ConfigurationProperties注解,而没有使用@Component,那么在IOC容器中是获取不到properties 配置文件转化的bean。

简单来说@EnableConfigurationProperties 相当于把使用 @ConfigurationProperties 的类进行了一次注入。


@ConditionalOnProperty 属性条件判断,判断指定的属性是否有指定的值,满足条件才会初始化bean。


类似UserAutoConfigure这样的自动化配置类是所有自动化配置组件的核心入口。

我们需要的就是在引入了user-spring-boot-starter的依赖后,在spring容器启动的时候,加载到这个自动化配置类,那么就可以初始化UserClient,完成自动化配置。


加载自动化配置类的三种方式


由于Spring boot默认扫描的是跟启动类平级的包。如果我们的Start跟启动类不在同一个主包下,那么就需要通过其他手段使得容器启动加载到UserAutoConfigure自动化配置类。


方式一:创建spring.factories属性配置文件

在user-spring-boot-starter工程下的/resources/META-INF目录下创建spring.factories属性配置文件,并在里面指定自动化属性配置类的全路径。


org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.laowan.user.autoconfig.UserAutoConfigure

这是由于在spring boot开启了自动化配置注解后,在容器启动时,会自动加载所有

/resources/META-INF下的spring.factories文件,读取org.springframework.boot.autoconfigure.EnableAutoConfiguration配置属性,组成一个集合,然后去遍历加载所有的自动化配置类。


建立demo工程测试:

1、引入user-spring-boot-starter的依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>com.laowan</groupId>
    <artifactId>user-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>


2、配置属性文件

spring.user.enabled=true
spring.user.name=laowan


3、编写单元测试类

@SpringBootTest
@Slf4j
class DemoApplicationTests {
    @Autowired
    UserClient userClient;
    @Test
    void userClientTest() {
        log.info(userClient.getName());
    }
}


4、执行结果

41.png

说明我们的自动化配置生效


方式二:通过定义@EnableXXX注解来加载自动化配置文件

在user-spring-boot-starter工程下,新建@EnableUserClient注解,其中最核心的是通过

@Import注解注入了UserAutoConfigure.class。这样在引用工程的启动类上只要添加了@EnableUserClient注解,那么就会加载到UserAutoConfigure自动化配置类


```javascript
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({UserAutoConfigure.class})
public @interface EnableUserClient {
}


测试:

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


先注释掉spring.factories中的配置项,然后执行单元测试,正确打印出配置属性spring.user.name的值,说明我们的自动化配置生效。


方式三:通过@SpringBootApplication注解指定扫描的基础包路径


在测试工程demo中,配置@SpringBootApplication的属性scanBasePackages

@SpringBootApplication(scanBasePackages = {"com.laowan.demo","com.laowan.user.autoconfig"})
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}


通过@SpringBootApplication注解的scanBasePackages 属性,指定扫描的包路径。

这里注意,一定要首先指定自己工程的根路径,然后再执行自动化配置类的包路径。

不然就只会扫描自动化配置类的包路径,自己工程就不会扫描导致启动出错。


测试:

执行单元测试,发现配置属性spring.user.name的值仍然可以正常打印,说明我们的自动化配置成功。


三种方式的比较:

三种加载自动化配置的方式,其核心都是解决Spring boot工程启动只会默认扫描跟启动类平级的包,导致其他不同包下的自动化配置类XXXAutoConfigure.class加载不到的问题。

方式一是通过spring.factories文件中配置org.springframework.boot.autoconfigure.EnableAutoConfiguration属性指定自动化配置类XXXAutoConfigure.class的全路径,是最主流的方式。

方式二通过自定义@EnableXXX注解并结合@Import注解加载自动化配置文件,在很多组件中也很常见,比如:


@EnableResourceServer

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({ResourceServerConfiguration.class})
public @interface EnableResourceServer {
}


@EnableDiscoveryClient

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({EnableDiscoveryClientImportSelector.class})
public @interface EnableDiscoveryClient {
    boolean autoRegister() default true;
}


方式三主要是对自动化配置原理的一种验证,实际项目中不推荐。


自动化配置原理核心:

就是想办法在spring容器启动的时候,扫描到自动化配置类,然后根据属性类和条件注解去声明Bean,完成自动化配置。


实现配置项提示功能


在user-spring-boot-starter工程的/resources/META-INF目录下创建spring-configuration-metadata.json

{
  "properties": [
    { "name": "spring.user.name",
      "defaultValue": "laowan",
      "description": "用户名称.",
      "type": "java.lang.String"
    },
    { "name": "spring.user.enabled",
      "defaultValue": false,
      "description": "是否启用user组件.",
      "type": "java.lang.Boolean"
    }
  ]
}


这样在引用工程中配置相关属性,就会出现提示了。

40.png


通用规定


1、spring官方自己定义的starter组件,命名规则:spring-boot-starter-组件名

如:

spring-boot-starter-web

spring-boot-starter-jdbc

spring-boot-starter-security


非官方定义的start组件,命名规则:组件名-spring-boot-starter

如:

mybatis-spring-boot-starter


2、自动化配置类命名:XXXAutoConfiguration


3、starter组件的常规目录结构分析

一般分为2个工程,一个xxx-spring-boot-starter工程,通过spring.provides指定依赖服务模块;

一个xxx-spring-boot-starter-autoconfigure模块,通过定义spring.factories指定自动化配置文件加载路径,定义spring-configuration-metadata.json实现自动化配置。

39.png


核心注解


在构建starter的过程中,涉及到一些注解

@EnableAutoConfiguration 开启自动化配置功能,包含在@SpringBootApplication注解中,可以通过exclude属性,过滤掉一些不需要开启自动化配置的组件。


@Import 通过快速导入的方式实现把实例加入spring的IOC容器中,@Import只能用在类上


@ConfigurationProperties(“spring.user”) 加载前缀为spring.user的属性去配置当前类,但是并不会加载到spring容器中,需要配合@Component或者@EnableConfigurationProperties去使用。

@EnableConfigurationProperties(UserPorperties.class) 使 使用了@ConfigurationProperties注解配置的类生效,也就是注入到spring容器中


条件注解@Conditional

可以放在加了@Configuration的配置类上面,也可以放在使用@Bean定义bean的时候。用来判断是否开启配置或是否注入bean。

@ConditionalOnBean:当容器中有指定的Bean的条件下

@ConditionalOnClass:当类路径下有指定的类的条件下

@ConditionalOnExpression:基于SpEL表达式作为判断条件

@ConditionalOnJava:基于JVM版本作为判断条件

@ConditionalOnJndi:在JNDI存在的条件下查找指定的位置

@ConditionalOnMissingBean:当容器中没有指定Bean的情况下

@ConditionalOnMissingClass:当类路径下没有指定的类的条件下

@ConditionalOnNotWebApplication:当前项目不是Web项目的条件下

@ConditionalOnProperty:指定的属性是否有指定的值

@ConditionalOnResource:类路径下是否有指定的资源

@ConditionalOnSingleCandidate:当指定的Bean在容器中只有一个,或者在有多个Bean的情况下,用来指定首选的Bean

@ConditionalOnWebApplication:当前项目是Web项目的条件下


总结


1、自动化配置的原理:

(1)、加载自动化配置类

通过@EnableAutoConfiguration开启自动化配置机制,原理是通过类加载器去扫描目录下所有spring.factories文件,读取org.springframework.boot.autoconfigure.EnableAutoConfiguration属性,然后去加载XXXAutoConfigure自动化配置类。这个是通用的加载方式,适合批量默认自动开启的组件。


针对某些特定组件,没有定义spring.factories文件,则需要通过在启动类上添加@EnableXXX的注解,通过@Import导入指定的自动化配置类,这种方式适合单一控制,默认不开启自动化配置的组件。


(2)、根据读取到的自动化配置类,完成相关配置过程

XXXAutoConfigure自动化配置类中根据spring boot相关注解,读取相关属性文件,并根据@Conditional条件注解判断是否开启自动化配置,是否实例化Bean。


2、自动化配置类加载的三种方式


3、怎么自定义一个starter组件以及相关的规范


4、自动化配置过程中,常见注解的说明


实战代码Git地址:https://github.com/StarlightWANLI/auto-config.git

目录
相关文章
|
14天前
|
Java Spring
【Spring】方法注解@Bean,配置类扫描路径
@Bean方法注解,如何在同一个类下面定义多个Bean对象,配置扫描路径
140 73
|
15天前
|
Java 数据库连接 Maven
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
自动装配是现在面试中常考的一道面试题。本文基于最新的 SpringBoot 3.3.3 版本的源码来分析自动装配的原理,并在文未说明了SpringBoot2和SpringBoot3的自动装配源码中区别,以及面试回答的拿分核心话术。
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
|
14天前
|
Java Spring
【Spring配置相关】启动类为Current File,如何更改
问题场景:当我们切换类的界面的时候,重新启动的按钮是灰色的,不能使用,并且只有一个Current File 项目,下面介绍两种方法来解决这个问题。
|
14天前
|
Java Spring
【Spring配置】idea编码格式导致注解汉字无法保存
问题一:对于同一个项目,我们在使用idea的过程中,使用汉字注解完后,再打开该项目,汉字变成乱码问题二:本来a项目中,汉字注解调试好了,没有乱码了,但是创建出来的新的项目,写的注解又成乱码了。
|
14天前
|
Java Spring
【Spring配置】创建yml文件和properties或yml文件没有绿叶
本文主要针对,一个项目中怎么创建yml和properties两种不同文件,进行配置,和启动类没有绿叶标识进行解决。
|
22天前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
76 14
|
19天前
|
XML Java 数据格式
Spring容器Bean之XML配置方式
通过对以上内容的掌握,开发人员可以灵活地使用Spring的XML配置方式来管理应用程序的Bean,提高代码的模块化和可维护性。
56 6
|
21天前
|
XML Java 数据格式
🌱 深入Spring的心脏:Bean配置的艺术与实践 🌟
本文深入探讨了Spring框架中Bean配置的奥秘,从基本概念到XML配置文件的使用,再到静态工厂方式实例化Bean的详细步骤,通过实际代码示例帮助读者更好地理解和应用Spring的Bean配置。希望对你的Spring开发之旅有所助益。
85 3
|
3月前
|
机器学习/深度学习 人工智能 运维
构建高效运维体系:从自动化到智能化的演进
本文探讨了如何通过自动化和智能化手段,提升IT运维效率与质量。首先介绍了自动化在简化操作、减少错误中的作用;然后阐述了智能化技术如AI在预测故障、优化资源中的应用;最后讨论了如何构建一个既自动化又智能的运维体系,以实现高效、稳定和安全的IT环境。
90 4
|
3月前
|
运维 Linux Apache
,自动化运维成为现代IT基础设施的关键部分。Puppet是一款强大的自动化运维工具
【10月更文挑战第7天】随着云计算和容器化技术的发展,自动化运维成为现代IT基础设施的关键部分。Puppet是一款强大的自动化运维工具,通过定义资源状态和关系,确保系统始终处于期望配置状态。本文介绍Puppet的基本概念、安装配置及使用示例,帮助读者快速掌握Puppet,实现高效自动化运维。
72 4