1.场景启动器的原理是什么?
xxx-spring-boot-starter
的作用是负责导入xxx-spring-boot-starter-autoconfigure
的依赖,而场景启动器真正的逻辑其实都在xxx-spring-boot-starter-autoconfigure
当中。
xxx-spring-boot-starter-autoconfigure
中会使用一个XXXProperties
的类去绑定application.yaml
或者application.properties
中的某个前缀的配置,并将该组件导入到容器当中。这样后续我们想要配置文件中的内容,只需要从容器中拿到这个类就可以拿到相关的配置。
XXXAutoConfiguration
配置类负责给容器中导入相应的组件,一般使用条件装配的方式进行导入,也就是如果用户自定义了相关的组件,那么我们就不导入相关的组件,而如果我们没有自定义相关的组件,那么容器中就通过配置文件的配置信息(XXXProperties
),给容器中装配一个组件。
比如我们来看Spring-Data-Redis
的自动装配:
2.开始自定义场景启动器
2.1 创建一个项目test,并建立两个模块
两个模块一般叫xxx-spring-boot-starter
和xxx-spring-boot-starter-autoconfigure
2.2 引入相关依赖
在xxx-spring-boot-starter
里引入xxx-spring-boot-starter-autoconfigure
的依赖
<dependencies>
<dependency>
<groupId>com.wanna</groupId>
<artifactId>wanna-spring-boot-starter-autoconfigure</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
在xxx-spring-boot-starter-autoconfigure
中引入spring-boot-starter
的依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
2.3 开始编写代码
xxx-spring-boot-starter
中什么都不做...只需要写xxx-spring-boot-starter-autoconfigure
的逻辑
编写一个HelloService
类,简单逻辑:给输入的name
参数,加上指定的前缀/后缀并进行输出的sayHello
方法
public class HelloService { //默认不要放在容器中,使用条件装配进行装配
private HelloProperties helloProperties;
public String sayHello(String name) {
return helloProperties.getPrefix() + ":" + name + ">>>" + helloProperties.getSuffix() + "!";
}
public HelloProperties getHelloProperties() {
return helloProperties;
}
public void setHelloProperties(HelloProperties helloProperties) {
this.helloProperties = helloProperties;
}
}
需要注意的是,这个组件默认不要放在容器中!需要通过配置类进行条件装配!HelloProperties
的建立见下文,它的主要作用是和配置文件中指定前缀的配置进行绑定。
@ConfigurationProperties(prefix = "wanna.hello")
public class HelloProperties {
private String prefix;
private String suffix;
public String getSuffix() {
return suffix;
}
public void setSuffix(String suffix) {
this.suffix = suffix;
}
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
}
下面就到了关键环节,编写一个自动配置类,一般叫XXXAutoConfiguration
:
@Configuration
@EnableConfigurationProperties(HelloProperties.class) //开启配置注解,这个组件中的所有属性将从配置文件中获取,并把组件放到容器中
public class HelloServiceAutoConfiguration {
@Bean
@ConditionalOnMissingBean({HelloService.class}) //在容器中缺少这个Bean的时候才往容器中注入,如果容器中已经有了就不用注入了
public HelloService helloService(@Autowired HelloProperties helloProperties) {
HelloService helloService = new HelloService();
helloService.setHelloProperties(helloProperties);
return helloService;
}
}
使用@EnableConfigurationProperties
注解开启属性绑定,将配置文件中指定前缀的配置文件和HelloProperties
进行绑定(绑定配置文件的类一般叫XXXProperties
)。并使用@ConditionalOnMissingBean
注解标明,只有在缺少我们自定义的Bean
的时候才将该组件导入到容器当中。
完成了代码的编写之后,我们需要完成的是,需要往容器中导入哪些自动配置类的相关配置:
image.png在resources文件夹下建立META-INF
文件夹,建立一个spring.factories
配置文件
往其中添加如下内容,用来标明我们想要往容器中导入的XXXAutuConfiguration
组件的全类名
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.wanna.hello.auto.HelloServiceAutoConfiguration
2.4 打包进maven本地仓库
依次完成xxx-spring-boot-starter-autoconfigure
和xxx-spring-boot-starter
模块的打包,就放到我们maven本地仓库当中。
2.5 重新创建一个项目进行测试
引入我们刚刚打包好的xxx-spring-boot-starter
的依赖(并且引入Web的场景启动器方便进行测试)
<dependency>
<groupId>com.wanna</groupId>
<artifactId>wanna-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
编写application.yaml
或者application.properties
配置文件,配置我们自动装配包中需要提供的前缀的配置:
wanna.hello.prefix=hello
wanna.hello.suffix=666
编写测试的Controller
@RestController
public class HelloController {
HelloService helloService;
@Autowired
public HelloController(HelloService helloService) {
this.helloService = helloService;
}
@RequestMapping("/sayHello/{name}")
public String sayHello(@PathVariable("name") String name) {
return helloService.sayHello(name);
}
}
在浏览器中进行测试:
image.png发现装配成功,既然是条件装配我们自然还得测试自己自定义给容器中导入一个 HelloService
能否成功?下面编写一个Spring的配置类:
@Configuration
public class Config {
@Bean
public HelloService helloService() {
HelloService helloService = new HelloService();
HelloProperties properties = new HelloProperties();
properties.setPrefix("666");
properties.setSuffix("777");
helloService.setHelloProperties(properties);
return helloService;
}
}
在浏览器中进行测试:
image.png我们发现我们做到了条件装配,如果我们自己往容器中导入了相关的组件,那么自动配置类就不会导入相关的组件,而如果我们没配置,那么场景启动器会帮我们自动导入相关的组件。
网友评论