Springboot系列-自定义starter
前言:用过springboot的各位应该都知道,Springboot相对于Spring/SpringMVC要方便的多,为什么呢?这主要还是归功于Starter,其实Starter也是基于Spring/SpringMVC基础上实现的,因为Starter带来了许多的自动化配置,所以在我们开发的时候省了不少力
理解Starter
那么Starter是基于什么才能够实现众多自动化配置的呢?其实Starter的核心注解就是@Conditional,当classpath下面存在某一个class时,这个配置才会生效
自定义Starter
定义Starter
1.首先创建一个普通的新的maven项目,创建完成之后添加Starter的自动化配置类如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.1.8.RELEASE</version>
</dependency>
配置完之后其实我们可以通过源码看到,好多自动化配置已经引入进来了
2.配置完成之后创建一个DemoProperties类,用来接收application.properties中注入的值,如下:
@ConfigurationProperties(prefix = "test")
public class DemoProperties {
private String name = "王先森";
private String hobby = "Coding";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
}
以上这个DemoProperties配置类的意思就是直接将application.properties里面的属性值注入到该实例中,@ConfigurationProperties 类型安全的属性注入,即将 application.properties 文件中前缀为 javaboy 的属性注入到这个类对应的属性上
application.prpoerties配置文件内容如下:
test.name = wxy
test.hobby = basketball
3.配置完DemoProperties之后,在定义一个DemoService类并定义个方法如下:
public class DemoService {
private String name;
private String hobby;
public String doSomething() {
return name + " do " + hobby + " !";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
}
上面这个DemoService意思就是很简单的一个类,添加了个doSomething方法,之后再对应文件将该类注入之后,传入属性值调用该方法
4.接下来要做的是非常关键,就是关于自动配置的定义,因为之前我们可能用的都是别人定义的,所以这次需要自己去定义
@Configuration
@EnableConfigurationProperties(DemoProperties.class)
@ConditionalOnClass(DemoService.class)
public class DemoServiceAutoConfiguration {
@Autowired
DemoProperties demoProperties;
@Bean
DemoService demoService(){
DemoService demoService = new DemoService();
demoService.setName(demoProperties.getName());
demoService.setHobby(demoProperties.getHobby());
return demoService;
}
}
针对以上一段自动配置,解释如下:
- Configuration:表示这是一个配置类
- EnableConfigurationProperties:此注解是为了使之前配置的@ConfigurationProperties 生效
- @ConditionalOnClass :表示项目当前classpath下存在DemoService时,后面的配置才会生效
- 自动配置类中首先注入 DemoProperties ,该实例中有在 application.properties 中配置的相关数据
- 提供一个 DemoService 的实例,将 DemoProperties 中的值注入进去
5.自动化配置类基本完成,接下来还需要一个 spring.factories 文件,那么这个文件是干什么用的呢?我们知道Springboot项目中有一个启动类,该启动类包含了@SpringBootApplication 注解,这个注解的定义如下:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {}
根据上面我们可以看出其实SpringBootApplication 是一个组合注解,它包含了如上注解,其最重要和关键的三个注解并解释如下:
- @SpringBootConfiguration:此注解为Springboot配置注解,如下又在该注解中又包含如下注解:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
- @EnableAutoConfiguration:开启自动配置注解,只有开启了这个自动配置之后自动配置才会生效,其注解又包含如下注解:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
- @ComponentScan:这个注解在有一个主要的功能就是配置注解扫描,可以自定义去配置扫描的范围
6.在 Maven 项目的 resources 目录下创建一个名为 META-INF 的文件夹,然后在文件夹中创建一个名为 spring.factories 的文件,文件内容如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.wxy.entity.DemoServiceAutoConfiguration
动化配置类的路径配置完成,如此之后我们的自动化配置类就算完成了
本地安装
我们将我们写好的Starter项目进行打包,如下:
双击完成后,这个 Starter 就安装到我们本地仓库了,其实这个时候我们从该路径可以发现他打包成了一个jar包,如下:
那么如何使用它呢?
使用Starter
新建一个普通的 Spring Boot 工程,创建成功之后,加入自定义 Starter 的依赖,如下:
<dependency>
<groupId>com.example</groupId>
<artifactId>emptyMavenProject</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
此时我们引入了上面自定义的 Starter ,也就是说项目中现在有一个默认的 DemoService 实例可以使用,关于此实例的数据,可以在 application.properties 中进行配置,如下:
test.name = Wang sir
test.hobby = Coding
配置完成后,可选择在单元测试方法中注入 DemoSerivce 实例来使用,代码如下:
@SpringBootTest(classes = App.class)
class TeststarterApplicationTests {
@Autowired
DemoService demoService;
@Test
public void contextLoads() {
System.out.println(demoService.doSomething());
}
}
执行运行结果如下:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.1.RELEASE)
2019-12-03 15:16:57.423 INFO 19712 --- [ main] c.e.t.TeststarterApplicationTests : Starting TeststarterApplicationTests on Wangxinyao with PID 19712 (started by Administrator in E:\IDEAWorkSpace\teststarter)
2019-12-03 15:16:57.430 INFO 19712 --- [ main] c.e.t.TeststarterApplicationTests : No active profile set, falling back to default profiles: default
2019-12-03 15:17:00.216 INFO 19712 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-12-03 15:17:00.754 INFO 19712 --- [ main] c.e.t.TeststarterApplicationTests : Started TeststarterApplicationTests in 4.157 seconds (JVM running for 6.18)
Wang sir do Coding !
2019-12-03 15:17:01.054 INFO 19712 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
结语:基本上对于自定义Starter配置的讲解就到这里了,通过自定义Starter,可以把之前的项目通过打包注入到新的项目中,便捷开发