SpringBoot配置原理
SpringBoot配置原理
SpringBoot主要的中心思想是
- 约定大于配置
所以,一般来说在能默认满足的情况下是不进行额外的改变或者配置的
这样可以尽量做到开箱即用!也可以根据自己需要修改相应的部分配置
==而SpringBoot的核心也就是自动装配配置,其仿造了 Java SPI (服务提供发现机制)的一种类加载机制==
- 可以用来拓展框架和替换组件
- 常见的框架例子有
- JDBC
- SLF4J
Starter(启动器) 分析
在 SpringBoot 中需要导入相应的包都需要写一个相对应的 Starter
而 Starter 中一般不进行代码的编写,只做其他依赖的管理和集中
- 这样的好处是
- 一键式导入:导入相应的启动器(starter)后,会将该starter需要的包一并导入
- 可读性强:代码的编写是在本身原本的框架或者依赖中
- 符合SpringBoot的思想:可以再自定义一个框架的 autoconfiguration ,这样也可以进行默认的配置做到开箱即用
示例:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot</artifactId>
<version>2.2.0</version>
</parent>
<!-- starter本身只做依赖集中管理,不编写任何代码 -->
<artifactId>mybatis-spring-boot-starter</artifactId>
<name>mybatis-spring-boot-starter</name>
<properties>
<module.name>org.mybatis.spring.boot.starter</module.name>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- 编写的专用配置模块 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
</dependency>
</dependencies>
</project>
自定义 Starter
对以上 启动器 进行刨析了解后 ,如果想要自定义一个能够符合SpringBoot的框架,需要以下 三个模块
- spring-boot-hello:基础业务功能模块
- spring-boot-starter-hello:启动器
- spring-boot-autoconfigurer-hello:自动配置依赖
spring-boot-hello
首先创建一个基础的业务功能,实现框架基本实现代码。以下示例将用个简单代码进行演示
package com.test;
public class HelloWorldService {
public void test(){
System.out.println("Hello World!");
}
}
项目结构:
spring-boot-autoconfigurer-hello (关键)
然后创建一个自动配置和配置获取的项目
- autoconfigurer 项目需要导入以下依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.mianju</groupId>
<artifactId>spring-boot-hello</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
因为会使用到SpringBoot的注解标注 所以需要SpringBoot的依赖。
接着创建一个自动配置类:
@Configuration(proxyBeanMethods = false) //声明该类为配置类
@ConditionalOnWebApplication //当运行在web应用时,该配置类才会生效
@EnableConfigurationProperties(HelloWorldProperties.class) //开启对HelloWorldProperties的配置
public class HelloWorldAutoConfiguration {
Logger logger = Logger.getLogger(this.getClass().getName());
@Autowired
HelloWorldProperties properties; //注入HelloWorldProperties
@Bean
@ConditionalOnMissingBean // 当没有这个bean时,才会创建该bean 类似自动配置的bean
// 如果需要满足自己的需要可自行创建同名Bean进行替换
public HelloWorldService helloWorldService(){
logger.info("自定义starter项目已启动!");
logger.info("读取到自定义配置:"+properties.getValue());
return new HelloWorldService();
}
}
根据上面的HelloWorldProperties.class
所以还需要创建一个配置文件的 属性类
@ConfigurationProperties("hello.world") // 声明该类为属性类
public class HelloWorldProperties {
private String value; // 只有一个value属性
public void setValue(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
最后在resources
文件夹下 创建以下文件
- ==因为约定大于配置,所以这个文件和路径是不能有变动的==
- 该文件表示要加载的自动配置类的位置
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
文件内容也就是自动配置类的 全类名:
com.test.autoconfigure.HelloWorldAutoConfiguration
项目结构:
spring-boot-starter-hello
关于启动器就简单了,因为启动器没有代码,它存在的目的就是将 自动配置类 和 框架业务代码 的依赖进行一个统一整理
然后maven导入starter后就会自动将他所需要的依赖导入,所以只需要导入启动器就可以简单的导入所有的东西
<dependencies>
<dependency>
<groupId>cn.mianju</groupId>
<artifactId>spring-boot-autoconfigure-hello</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.mianju</groupId>
<artifactId>spring-boot-hello</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
所以只需要保留一个 pom.xml 文件就可以了
项目结构:
总结
其实SpringBoot的自动装配核心就在于
- spring-boot-autoconfigurer-xxx
- 自动配置类
- 配置属性类
- resources中的配置类声明文件
因为springboot源码中有这么一段:
public static ImportCandidates load(Class<?> annotation, ClassLoader classLoader) {
Assert.notNull(annotation, "'annotation' must not be null");
ClassLoader classLoaderToUse = decideClassloader(classLoader);
//这里直接获取 META-INF/spring/注解类名.imports 中的所有内容
String location = String.format("META-INF/spring/%s.imports", annotation.getName());
...
}
它会获取符合该文件名下的所有配置类和类中的bean并且对应的自动进行配置
所以他能根据你提供的文件去找到你的配置类与属性类
spring.factories
是用于对添加包以外的类至spring容器的成为beanMETA-INF/spring/注解类名.imports
是自动导入并加载配置类的地方
但是其实org.springframework.boot.autoconfigure.AutoConfiguration.imports
文件功能和Sping.factories
的**==作用是一样==**的
这个用法是SpringBoot 2.7以后出现的,目的也是为引入外部的包
把外部bean纳入到Spring容器,实现外部组件与Spring的集成,主要的区别在于引入的方式有些不同,spring.factories
这种方式是在resources下创建/META-INF/spring.factories
配置文件,内部是key-value的形式
这种则是创建/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
内部是具体的要导入到Spring环境的中的配置类。
==两种方式有一些区别,以前是应该是用第一种来实现,不过都是用来实现自动装配的。==