参考:
https://www.jianshu.com/p/fdb574e1f77c
前言:
SpringBoot在java中的地位简直是至尊的存在,非常的好用。Spring Boot有四大神器,分别是auto-configuration、starters、cli、actuator,我们用各种中间件的话就是各种starter 对应版本依赖引用,然后就是配置属性文件,就可以用了,其实工作当中,我们可以把一些通用的方法,服务来封装成starter,本文来交大家进行手动实现一个starter,满足我们以后工作的需要。
1.源码中的starter和自动配置:
Spring boot开发的时候我们不需要像Springmvc一样各种xml的各种配置写,开箱即用。看源码的话发现这个实现是基于:spring-boot-autoconfigure依赖。里面包含了很多其他的依赖包:
看图:
[外链图片转存中…(img-FzhzENHS-1623147296931)]
看源码里面都有个一个xxxxAAutoConfiguration的类:
rabbitmq:
[外链图片转存中…(img-mph3WCif-1623147296935)]
其中注解说明:
1.@Configuration注解表示这是一个配置类,用过Spring Boot的朋友都应该知道是什么东西,不多做解释了。
2.@ConditionalOnClass({RabbitTemplate.class, Channel.class}),该注解表示当KafkaTemplate.class被加载到JVM中,才会对配置类进行初始化,简单理解就是把他当做if语句来看。
3.@EnableConfigurationProperties({RabbitProperties.class}),加载属性配置类的注解,有这个注解,KafkaProperties才会作用于应用上下文中。
4.@Import({RabbitAnnotationDrivenConfiguration.class}),Spring 的基础注解,不多说了。
Spring boot是通过两个路径来确定自动配置类的,一个是@EnableAutoConfiguration注解,二是spring.factories配置文件,改文件在META-INF目录下面,里面配置了配置项:org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration。
@SpringBootApplication注解是包含@EnableAutoConfiguration注解的,注解里面的核心注解是:@Import(AutoConfigurationImportSelector.class)注解,里面涉及到代码:
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
就是加载资源配置文件。
流程总结的话就是:应用配置类注解@EnableAutoConfiguration-》导入AutoConfigurationImportSelector-》启动应用加载spring.factories里的配置信息(通过AutoConfigurationImportSelector 、getCandidateConfigurations)-》如果缺少相关依赖类存在,就不会触发执行,触发成功,就会执行。
其中spring.factories不仅仅包含自动配置相关信息,还包含其他的信息。
2.手动实现starter:
我们用springboot的时候加入spring-boot-starter-web依赖,不需要任何配置,就可以直接构建web应用,可见自动配置的厉害,spring是一个扩展性很强的框架,支持我们自定义符合需求的starter。
一个完整的starter包含两个部分:
1.提供自动配置功能的自动配置模块
2.做到开箱即用,提供依赖关系管理的组件模块
spring-boot-autoconfigure中包含的AutoConfiguration都是Spring家族的项目,自己封装的starter就需要自己写xxxAutoConfiguration。
添加依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
导入配置代码:
@ConfigurationProperties(prefix = "yeonon.car")
public class CarProperties {
private static final String DEFAULT_NAME = "BWM";
private static final String DEFAULT_COLOR = "white";
private static final Integer DEFAULT_AGE = 1;
private String name = DEFAULT_NAME;
private String color = DEFAULT_COLOR;
private Integer age = DEFAULT_AGE;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
//getter 和 setter必须要有,否则属性注入会有问题
}
service代码:
public class CarService {
private Car car;
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
}
自动配置类
@Configuration
@ConditionalOnClass(CarService.class)
@EnableConfigurationProperties(value = CarProperties.class)
public class CarAutoConfiguration {
@Autowired
private CarProperties carProperties;
@Bean
@ConditionalOnMissingBean(CarService.class)
// @ConditionalOnProperty(value = "yeonon.car.server.configuration.auto.enabled", matchIfMissing = true)
public CarService carService() {
CarService carService = new CarService();
Car car = new Car();
car.setName(carProperties.getName());
car.setColor(carProperties.getColor());
car.setAge(carProperties.getAge());
carService.setCar(car);
return carService;
}
}
注解说明:
@Configuration注解是要有的,否则无法生效。
@ConditionalOnClass(CarService.class),原则上可有可无,但作为一个健壮的starter,还是有的好,作为一个“防御措施”。
@EnableConfigurationProperties(value = CarProperties.class),要使用属性系统,就需要把属性类加入到应用上下文中。
@Bean就是定义一个Bean了,代码逻辑没什么可说的,无法就是创建对象,然后构建对象并返回而已。关键在于@ConditionalOnMissingBean注解和@ConditionalOnProperty注解。@ConditionalOnMissingBean注解的意思就是如果应用中不存在CarService的Bean,那么就执行下面的方法构建一个Bean,已经存在的话,就不会调用下面的方法了,这意味着用户可以自己创建Bean来覆盖系统默认配置的Bean。@ConditionalOnProperty就是当配置存在的时候,才会执行Bean的构建。
然后再资源文件夹下面创建META-INF文件夹,创建spring.factories,配置:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
top.yeonon.stater.test.CarAutoConfiguration
应用starter:
@Autowired
private CarService carService;
@GetMapping("car")
public Car getMyCar(@AutoLoginInfo LoginInfo loginInfo, @AutoUserInfo UserInfo userInfo) {
System.out.println(loginInfo);
System.out.println(userInfo);
return carService.getCar();
}
属性配置:
## 注意前缀是yeonon.car,也是在CarProperties类里配置好的
yeonon.car.name=MSLD
yeonon.car.age=2
yeonon.car.color=black
总结
上面的手动实现starter其实是一个标准的实现过程,但是呢,我们实际开发其实并不需要那么麻烦,两个注解搞定starter,第一个注解@EnableMonitor注解在springboot启动类上,然后里面的注解实现:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Import({MetricsConfig.class, MonitorConfig.class})
public @interface EnableMonitor {
}
这样分别在Import里面的类去实现业务逻辑就可以。如果你有问题换用留言,如果你喜欢欢迎点赞,转发,赞赏。