自己动手写之手写一个starter
-
什么是starter?
starter是SpringBoot中的一个新发明,它有效的降低了项目开发过程的复杂程度,对于简化开发操作有着非常好的效果。提供一个开箱即用的组件。
-
手写一个starter
假设我们有个需求,我们需要序列化一个对象,当工程中存在FastJson的com.alibaba.fastjson.JSON类时使用FastJson序列化,如果不存在就则进行简单的toString操作。
我们首先定义一个接口有一个格式化方法
public interface FormatProcessor { //定义一个序列化的方法 <T> String format(T obj); }
然后这个接口有两个实现类,分别做不同序列化操作。
import com.alibaba.fastjson.JSON; public class JsonFormatProcessor implements FormatProcessor{ @Override public <T> String format(T obj) { return "JsonFormatProcessor:"+ JSON.toJSONString(obj); } }
import java.util.Objects;
public class StringFormatProcessor implements FormatProcessor{
@Override
public String format(T obj) {
return “StringFormatProcessor:”+Objects.toString(obj);
}
}定义一个Configuration类。
@Configuration
public class FormatAutoConfiguration {
@ConditionalOnMissingClass(“com.alibaba.fastjson.JSON”) // 如果不存在JSON类就加载
@Bean
@Primary // 如果有两个实现则优先加载这个
public FormatProcessor stringFormat() {
return new StringFormatProcessor();
}@ConditionalOnClass(name = “com.alibaba.fastjson.JSON”) // 如果存在JSON类
@Bean
public FormatProcessor jsonFormat() {
return new JsonFormatProcessor();
}
}定义一个自动配置类。
@Import(FormatAutoConfiguration.class)
@Configuration
public class HelloAutoConfiguration {@Bean
public HelloFormatTemplate helloFormatTemplate( FormatProcessor formatProcessor) {
return new HelloFormatTemplate(formatProcessor);
}
}template类
public class HelloFormatTemplate {
private FormatProcessor formatProcessor;
public HelloFormatTemplate(FormatProcessor formatProcessor) {
this.formatProcessor = formatProcessor;
}public String doFormat(T obj){
StringBuilder stringBuilder=new StringBuilder();
stringBuilder.append(“begin:Execute format”).append("
");
stringBuilder.append(“Obj format result:”).append(formatProcessor.format(obj)).append("
");
return stringBuilder.toString();
}
}使用spring boot的SPI机制把 HelloAutoConfiguration自动装配进spring容器。在spring.factories文件中定义
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
com.yhx.starter.autoconfiguration.HelloAutoConfiguration这样我们就写出了一个starter,实现了一个类似以RedisTemplate的HelloFormatTemplate的工具。那如果我们要使用外部化的配置也就要读取到application.yml文件的配置该怎么写呢? 首先我们写一个Properties类,并加上@ConfigurationProperties注解。
@ConfigurationProperties(prefix = HelloProperties.HELLO_FORMAT_PREFIX)
public class HelloProperties {
public static final String HELLO_FORMAT_PREFIX = “yhx.hello.format”;
private Map<String, Object> info;
public Map<String, Object> getInfo() {
return info;
}
public void setInfo(Map<String, Object> info) {
this.info = info;
}
}然后在HelloAutoConfiguration的自动装配的类中加上@EnableConfigurationProperties(HelloProperties.class),此时HelloAutoConfiguration类为
@Import(FormatAutoConfiguration.class)
@EnableConfigurationProperties(HelloProperties.class)
@Configuration
public class HelloAutoConfiguration {@Bean
// HelloProperties这时候的已经在spring容器中了,会自动去找查的
public HelloFormatTemplate helloFormatTemplate(HelloProperties helloProperties, FormatProcessor formatProcessor) {
return new HelloFormatTemplate(helloProperties, formatProcessor);
}
}这时候我们的Template可以改写为如下的
public class HelloFormatTemplate {
private FormatProcessor formatProcessor;
private HelloProperties helloProperties;
public HelloFormatTemplate(HelloProperties helloProperties,FormatProcessor formatProcessor) {
this.helloProperties=helloProperties;
this.formatProcessor = formatProcessor;
}public String doFormat(T obj){
StringBuilder stringBuilder=new StringBuilder();
stringBuilder.append(“begin:Execute format”).append("
");
stringBuilder.append(“HelloProperties:”).append(formatProcessor.format(helloProperties.getInfo())).append("
");
stringBuilder.append(“Obj format result:”).append(formatProcessor.format(obj)).append("
");
return stringBuilder.toString();}
}我们在使用这个这个starter的工程中在application.yml或者是application.properties中配置,就可以配置进这个序列化的bean中
yhx.hello.format.info.country=CN
yhx.hello.format.info.provice=HuNan
yhx.hello.format.info.city=shanghai
yhx.hello.format.info.org=xingren -
常见的starter之logger
我们在项目中加入logging starter的依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> <version>2.3.4.RELEASE</version> </dependency>
然后看一下spring-boot-starter-logging的jar包,发现里面并没有什么,这是为什么呢?
spring-boot-starter-logging-2.3.4.RELEASE.jar META-INF LICENSE.txt MANIFEST.MF NOTICE.txt
然后我们点进pom文件中的spring-boot-starter-logging看看
<?xml version="1.0" encoding="UTF-8"?> <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <!-- This module was also published with a richer model, Gradle metadata, --> <!-- which should be used instead. Do not delete the following line which --> <!-- is to indicate to Gradle or any Gradle module metadata file consumer --> <!-- that they should prefer consuming it instead. --> <!-- do_not_remove: published-with-gradle-metadata --> <modelVersion>4.0.0</modelVersion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> <version>2.3.4.RELEASE</version> <name>spring-boot-starter-logging</name> <description>Starter for logging using Logback. Default logging starter</description> <url>https://spring.io/projects/spring-boot</url> <organization> <name>Pivotal Software, Inc.</name> <url>https://spring.io</url> </organization> <licenses> <license> <name>Apache License, Version 2.0</name> <url>https://www.apache.org/licenses/LICENSE-2.0</url> </license> </licenses> <developers> <developer> <name>Pivotal</name> <email>info@pivotal.io</email> <organization>Pivotal Software, Inc.</organization> <organizationUrl>https://www.spring.io</organizationUrl> </developer> </developers> <scm> <connection>scm:git:git://github.com/spring-projects/spring-boot.git</connection> <developerConnection>scm:git:ssh://git@github.com/spring-projects/spring-boot.git</developerConnection> <url>https://github.com/spring-projects/spring-boot</url> </scm> <issueManagement> <system>GitHub</system> <url>https://github.com/spring-projects/spring-boot/issues</url> </issueManagement> <dependencies> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-to-slf4j</artifactId> <version>2.13.3</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>jul-to-slf4j</artifactId> <version>1.7.30</version> <scope>compile</scope> </dependency> </dependencies> </project>
里面就是一堆依赖,为什么空的也能实现自动装配呢?因为spring boot官方提供了装配,如果相关的类或者一类存在的话,所以logging的starter只需要添加一些依赖就可以。