前言
我们经常封装自己写的框架代码,用于重复使用,通过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本质没有太大的区别,但是自动化配置大大减少了程序的配置复杂度,方便开发专注于业务的开发能力。