1、starter启动原理
- starter-pom引入 autoconfigurer 包
- autoconfigure包中配置使用 META-INF/spring.factories 中 EnableAutoConfiguration 的值,使得项目启动加载指定的自动配置类
这里的autoconfigure指的是下面这个我们通过xxx-spring-boot-starter依赖的xxx-spring-boot-starter-autoconfigure - 编写自动配置类 xxxAutoConfiguration -> xxxxProperties
- @Configuration
@Conditional
@EnableConfigurationProperties
@Bean
引入starter — xxxAutoConfiguration — 容器中放入组件 ---- 绑定xxxProperties ---- 配置项
2、自定义starter
1、创建xxx-spring-boot-starter类
我们通过分析源码可以得知,springboot提供的starter,其实并没有定义什么内容,只是依赖了对应的starter的autoconfigure,通过导入starter去开启导入对应的组件
这里我们创建一个starter类:xiaoshuang-hello-spring-boot-starter
在pom.xml文件中去引入对应的xiaoshuang-hello-spring-boot-starter-autoconfigure
<?xml version="1.0" encoding="UTF-8"?>
<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>
<groupId>com.shuang</groupId>
<artifactId>xiaoshuang-hello-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.shuang</groupId>
<artifactId>xiaoshuang-hello-spring-boot-starter-autoconfigure</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
2、创建xxx-spring-boot-starter-autoconfigure
创建starter对应的autoconfigure,其中包含了我们定义的业务类,而业务类会使用**@Autowired**去导入xxxProperties,而对应的xxxProperties会使用@ConfigurationProperties去获取properties的值;
之后我们需要去创建对应的xxxAutoConfiguration,并使用@Configuration,@Conditionalxxx进行条件过滤,已确定是否开启该自动配置;使用@EnableAutoConfiguration将xxxProperties添加到IOC容器中,并开启指定类与properties文件对应前缀的绑定;在xxxAutoConfiguration中需要去定义返回值为要导入容器的组件,并使用@Bean添加到IOC容器
这里创建对应xiaoshuang-hello-spring-boot-starter的autoConfigure类:
xiaoshuang-hello-spring-boot-starter-autoconfigure
1、创建HelloProperties
package com.shuang.hello.bean;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @Author: 小爽帅到拖网速
*/
@ConfigurationProperties("xiaoshuang.hello")
public class HelloProperties {
private String prefix;
private String suffix;
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public String getSuffix() {
return suffix;
}
public void setSuffix(String suffix) {
this.suffix = suffix;
}
}
2、创建依赖HelloProperties的业务类
package com.shuang.hello.service;
import com.shuang.hello.bean.HelloProperties;
import org.springframework.beans.factory.annotation.Autowired;
/**
* @Author: 小爽帅到拖网速
*/
public class HelloService {
@Autowired
private HelloProperties helloProperties;
public String sayHello(String name) {
return helloProperties.getPrefix() + ": "+name +"---->"+helloProperties.getSuffix();
}
}
3、创建自动配置类并添加到IOC中
package com.shuang.hello.auto;
import com.shuang.hello.bean.HelloProperties;
import com.shuang.hello.service.HelloService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author: 小爽帅到拖网速
*/
@Configuration // 添加到IOC容器
/**
* @EnableConfigurationProperties(HelloProperties.class)
* 1、开启HelloProperties与对应的properties文件对应的前缀绑定
* 2、将HelloProperties加入到容器中
*/
@EnableConfigurationProperties(HelloProperties.class)
public class HelloServiceAutoConfiguration {
// 如果当前容器没有HelloService,就将执行以下方法将HelloService加入到容器中
// 如果当前容器有HelloService,就不会执行以下方法
@ConditionalOnMissingBean(HelloService.class)
@Bean
public HelloService helloService(){
return new HelloService();
}
}
4、resources下创建META-INF/spring-factories
我们在分析xxxAutoConfiguration是最终都会走到xxx组件对应的META-INF/spring-factories文件下
经过分析后我们可以知道,springboot的自动配置原理,最终通过META-INF/spring-factories,查找到对应的xxx.xxx.xxxAutoConfiguration(全类限定名),并运行这个类
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.shuang.hello.auto.HelloServiceAutoConfiguration
3、添加到maven仓库
1、先将xxx-spring-boot-starter-autoconfigure添加到maven中
2、再将xxx-spring-boot-starter添加到maven中,跟上面的是一样的操作
4、测试自定义starter
1、创建测试项目,并导入xxx-spring-boot-starter依赖
<dependency>
<groupId>com.shuang</groupId>
<artifactId>xiaoshuang-hello-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
2、创建测试Controller
package com.shuang.hello.controller;
import com.shuang.hello.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author: 小爽帅到拖网速
*/
@RestController
public class HelloController {
@Autowired
HelloService helloService;
@GetMapping("/hello")
public String sayHello(){
String hello = helloService.sayHello("郑爽");
return hello;
}
}
注意:如果遇到@Autowired失败,可以参考以下这篇文章
5、原理总结
我们在测试Controller中使用了@Autowired去自动导入了我们在hello-spring-boot-starter-autoconfigure定义的业务类,在自动导入之前,springboot就已经扫描完所有导入starter的类,最终会扫描到每个starter类依赖的xxxAutoConfigure下的META-INF/spring.factories,通过该文件获取到xxxAutoConfiguration的全类限定名,就会去加载我们写在xxx-spring-boot-xxxAutoConfigure项目下的xxxAutoConfiguration类,也就是我们前面定义的HelloServiceAutoConfiguration,通过判断是否执行创建HelloService,从而决定是否对HelloProperties.class进行下一步操作(开启与对应properties的前缀进行绑定以及添加到IOC容器)
在HelloServiceAutoConfiguration中使用**@ConditionalOnMissingBean(HelloService.class),如果我们在当前容器中也就是测试项目容器有HelloService.class的存在,也就不会去执行HelloServiceAutoConfiguration**下的某个对应方法
这里我们可以做个测试(当前容器以及存在HelloService.class)
package com.shuang.hello.config;
import com.shuang.hello.service.HelloService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author: 小爽帅到拖网速
*/
@Configuration
public class MyConfig {
@Bean
public HelloService helloService(){
return new HelloService();
}
}
可以看到当我们添加创建了HelloService并添加到IOC容器中,就不会去执行HelloServiceAutoConfiguration下对应的helloService()