自定义一个starter
原理:
什么是SPI?
SPI(Service Provider Interface)
机制是一种服务发现和加载机制。它允许开发者编写一个服务接口,然后通过在项目中使用服务提供者实现该接口的方式,实现对应的服务功能。
在Spring Boot中,SPI机制允许开发者通过定义接口和实现类的方式,实现对应的功能扩展。通过在META-INF/spring.factories配置文件中列出实现类,Spring Boot能够自动加载并使用这些扩展点,提供了灵活的定制和扩展能力
命名规则:
官方的starter:
spring-boot-starter-*
自己写的starter:
*-spring-boot-starter
一、意义
starter是一种非常重要的机制,能够抛弃以前繁杂的配置,将其统一集成进starter,应用者只需要在maven中引入starter依赖,SpringBoot就能自动扫描到要加载的信息并启动相应的默认配置。starter让我们摆脱了各种依赖库的处理,需要配置各种信息的困扰。SpringBoot会自动通过classpath路径下的类发现需要的Bean,并注册进IOC容器。
经常会有一些独立于业务之外的配置模块,我们经常将其放到一个特定的包下,然后如果另一个工程需要复用这块功能的时候,需要将代码硬拷贝到另一个工程,重新集成一遍,麻烦至极。如果我们将这些可独立于业务代码之外的功配置模块封装成一个个starter,复用的时候只需要将其在pom中引用依赖即可,SpringBoot为我们完成自动装配。
二、使用场景
动态数据源。
登录模块。
基于AOP技术实现日志切面
获取密码(与业务相关了)
三、定义步骤
1、打开IDEA
File>>New>>Project>>Empty Project
其中 Project name填自己的空项目名字(即空项目,父工程名字),我写的是boot-customer-starter 创建出空项目
2、创建场景启动器。打开空项目后会弹出New Module弹框
点击加号,选择Maven
, GroupId 我填的是com.atsinux
ArtifactId我填的是atsinux-hello-spring-boot-starter
它是场景启动器的名字,点击下一步的Module
name填写atsinux-hello-spring-boot-starter ,Content root 和Module file
location都是写的:D:\学习文件\mystudy\boot-customer-starter\atsinux-hello-spring-boot-starter
(这个路径很重要)
3、创建自动配置模块 点击加号,创建module,选择spring Initializr
Group填com.atsinux
ArtifactId我填的是atsinux-hello-spring-boot-starter-autoconfigure
,这个是自动配置器的名字
注意Module name填的是atsinux-hello-spring-boot-starter-autoconfigure
Content root 和Module file location路径写的是:
D:\学习文件\mystudy\boot-customer-starter\atsinux-hello-spring-boot-starter-autoconfigure
注意:这里的路径和上面的是在相同文件夹下的,要不然后面打包报错
4、创建好了一个工程下的两个模块,现在来引入jar
4.1、在atsinux-hello-spring-boot-starter的pom.xml中引入atsinux-hello-spring-boot-starter-autoconfigure
当成jar包引入,场景启动器对外引用,自动配置器提供自动装配功能
注意:这里几个要点:
1、整个父项目是Empty Project 项目
2、场景启动器是Maven项目
3、自动配置器是spring初始化向导spring Initializr 的springboot项目
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>atguigu-hello-spring-boot-starter-autoconfigure</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
4.2、在atsinux-hello-spring-boot-starter-autoconfigure的pom.xml中引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
删除autoconfigure多余的单元测试,主启动类,properties等
当其他项目继承本项目时,如果dependences中加上了
<optional>true</optional>
,表示当前依赖不向下传递,比如用户引入我的starter,我的jar包不会加载进用户的项目里
<scope>provided</scope>
,provided适合在编译和测试的环境,他和compile很接近,但是provide仅仅需要在编译和测试阶段,同样provide将不会被打包到lib目录下
<scope>runntime</scope>
, runntime这个scope,仅仅适用于运行环境,在编译和测试环境下都不会被使用
<scope>test</scope>
,scope为test表示依赖项目仅仅参与测试相关的工作,在编译和运行环境下都不会被使用,更别说打包了
5、写一个HelloService.java ,用于获取引用者配置的属性内容
引用工程的配置文件中以 atSinux.hello开头的属性会被读取被绑定进来
@ConfigurationProperties("atSinux.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;
}
}
6、写一个HelloService.java
这个是给引用者调用的方法所在:
/** * 默认不放入容器 */
public class HelloService {
@Autowired
private HelloProperties helloProperties;
public String sayHello(String userName){
return helloProperties.getPrefix()+":"+userName+">"+helloProperties.getSuffix();
}
}
7、写一个自动配置类HelloServiceAutoConfiguration.java
@Configuration
@EnableConfigurationProperties(HelloProperties.class)
public class HelloServiceAutoConfiguration {
@Bean
@ConditionalOnMissingBean(HelloService.class)//容器中没有HelloService的bean才放入
public HelloService helloService(){
HelloService helloService = new HelloService();
return helloService;
}
}
8.在resources下面建一个META-INF,再写入spring.factories
指定加载的配置类,也就是加载的入口指向哪个类
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.atsinux.hello.auto.HelloServiceAutoConfiguration
9.自动配置写完,分别执行clean、install(先执行自动装配器autoconfigure的,再执行场景启动器starter的),也就是把他们打成jar包放入maven库
10、测试 写一个单独的springboot工程,引入starter的jar包
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>atsinux-hello-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
在properties中配置 :
atsinux.hello.prefix="moning"
atsinux.hello.suffix="are you shotting?"
在控制层写一个方法调用:
@RestController
public class CustomerController {
@Autowired
private HelloService helloService;
@GetMapping("/hello")
public String getSay(){
return helloService.sayHello("老王");
}
}
那么启动后,访问该接口,就会按名字自定义输出