前言
我们经常封装自己写的框架代码,用于重复使用,通过jar依赖,代码触发来实现框架的插件的能力。在Spring-boot的框架中经常用到xxx-starter实现mybatis,mongodb,kafka等第三方中间件的服务,仅需在application等properties配置文件中写少量的配置即可实现。下面我来自行实现一个简单的starter。
starter的3要素
1)配置加载器
2)spring bean
3)配置文件与spring bean配置管理器
1. 定义starter project
分别定义3个目录,用于存放3要素。
pom依赖如下:加上lombok,更方便
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
</dependency>
</dependencies>
2. properties处理
SpringBoot在处理自定义application.properties或者application.yml配置文件内需要的配置参数的时候,提供了注解@ConfigurationProperties,将application.properties配置文件内的按照注解方式的配置参数映射到javabean的field内,并注入Spring的Bean容器中。
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@Data
@ConfigurationProperties(value = "org.ee")
public class HelloProperties {
private String starterDemo;
private boolean demoEnable;
}
这个配置注解用于配置我们定义的规则配置注入这个bean,value就是prefix默认方式
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ConfigurationProperties {
@AliasFor("prefix")
String value() default "";
@AliasFor("value")
String prefix() default "";
boolean ignoreInvalidFields() default false;
boolean ignoreUnknownFields() default true;
}
3. 自定义starter do something
我们自定义starter是为了对spring boot框架集成服务或者中间件的client端或者server端等,比如我们自定义service。此部分服务功能在spring boot启动的时候自动加载。
@Data
public class HelloService {
private String starterDemo;
private boolean demoEnable;
public String sayHello() {
if (demoEnable) {
return "hello:\t" + starterDemo + ",\ti do something";
} else {
return "i do nothing";
}
}
}
4. 管理配置bean与服务实现,自动化配置
//配置bean
@Configuration
//开启使用映射实体类,用于对自定义配置bean的创建,field的绑定
@EnableConfigurationProperties(HelloProperties.class)
//当存在HelloService类时初始化该配置类
@ConditionalOnClass(HelloService.class)
//application.properties或者application.yml文件存在对应配置信息时初始化该配置类
@ConditionalOnProperty
(
prefix = "org.ee",//存在配置前缀org.ee
value = "enabled",//开启
matchIfMissing = true//缺失检查
)
public class HelloAutoConfiguration {
@Autowired
private HelloProperties helloProperties;
@Bean
//当缺失HelloService实体bean时,才初始化HelloService到spring ioc容器
//用于自定义bean覆盖次bean实现进一步自定义能力
@ConditionalOnMissingBean
public HelloService buildDefaultHelloService(){
HelloService helloService = new HelloService();
helloService.setStarterDemo(helloProperties.getStarterDemo());
helloService.setDemoEnable(helloProperties.isDemoEnable());
return helloService;
}
}
@Configuration:配置bean,等同于@Component
@EnableConfigurationProperties:开启使用配置属性,value是我们配置实体参数ClassType,将配置实体javabean作为配置来源。其他SpringBoot内置
@Conditional注解
@ConditionalOnBean:当Spring Ioc容器内存在指定Bean的时候生效
@ConditionalOnClass:当Spring Ioc容器内存在指定Class的时候生效
@ConditionalOnExpression:匹配SpEL表达式
@ConditionalOnJava:匹配JVM版本
@ConditionalOnJndi:存在JNDI时
@ConditionalOnMissingBean:当Spring Ioc容器内不存在指定Bean
@ConditionalOnMissingClass:当Spring Ioc容器内不存在指定Class
@ConditionalOnNotWebApplication:当项目不是Web项目
@ConditionalOnProperty:指定的属性是否有指定的值
@ConditionalOnResource:类路径是否有指定的值
@ConditionalOnSingleCandidate:当指定Bean在Spring Ioc容器内只有一个,或者虽然有多个但是指定首选的Bean
@ConditionalOnWebApplication:当前项目是Web项目的条件
5. 自动加载的本质EnableAutoConfiguration
配置spring.factories
我们在src/main/resource目录下创建META-INF目录,然后创建文件spring.factories:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.ee.plugin.starter.config.HelloAutoConfiguration
配置后,spring boot的EnableAutoConfiguration注解在SpringBootApplication注解上,会自动加载我们写的HelloAutoConfiguration配置bean。
@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 {
6. starter使用
要使用我们的starter,需要mvn install 装载nexus库
在新project项目中依赖
<dependencies>
<dependency>
<groupId>com.feng.demo</groupId>
<artifactId>feng-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
</dependencies>
新建application.properties文件
编写测试controller
@RestController
public class HelloController {
@Autowired
private HelloService helloService;
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String sayHello(){
return helloService.sayHello();
}
}
启动,访问localhost:8080/hello
说明自定义starter生效。
总结
spring boot和spring MVC本质没有太大的区别,但是自动化配置大大减少了程序的配置复杂度,方便开发专注于业务的开发能力。