在学习Spring Boot的过程中,接触最多的就是starter。使用者可以把starter当成是一种服务——使得使用某个功能时不需要关注各种依赖库的处理,不需要具体的配置信息,由Spring Boot自动通过classpath路径下的类发现需要的Bean,并织入bean。而自动装配就是Springboot最大的特性。
举个例子,spring-boot-starter-jdbc这个starter的存在,使得我们只需要在Application下用@Autowired引入DataSource的bean就可以,Spring Boot会自动创建DataSource的实例。
下面我们用一个不是特别标准的方式定制一个我们自己的Starter。
首先先定义一下我们这个starter要干什么,我们的目的时演练构建Starter的过程,具体逻辑不重要,这里只是封装一个控制台打印类。
第一步:初始化项目
在一个spring-boot项目中新建一个子模块,这里使用的时maven,使用maven创建一个普通的Java项目即可。完成后在src/main/目录下面建立resource文件夹。
在pom.xml文件中引入依赖如下:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
</dependencies>
第二步:初始化项目结构
按下图结构创建完成包和类(熟悉后,不用按这里的步骤进行)。
第三步:编码Starter的核心类
首先是执行类,其实就是一个普通的Java Bean
public class LogCollector {
public void info(String info) {
System.out.println("Info: " + info);
}
public void error(String errorInfo) {
System.out.println("Error: " + errorInfo);
}
}
下面就是springboot-starter的核心之一了,自动装配的配置类
import com.leon.collector.LogCollector;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class LogCollectorAutoConfig {
@Bean(name = "logCollector")
public LogCollector logCollector() {
return new LogCollector();
}
}
配置类的类注解@Configuration是为了让springboot扫描识别用的,@Bean是让spring扫描到后把bean的实例放到Spring容器中进行管理。
最重要的一步来了,编写spring.factories文件。
在 src/main/resources 目录下新建 META-INF 文件夹,然后新建 spring.factories 文件,这个文件用于告诉Spring Boot有那些自动配置类需要处理,因此它的内容是
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.biz.LogCollectorAutoConfig -- 这个类就是上面????的配置类的全路径
第四步:使用
在某个模块的pom.xml引入上面的Starter
<dependency>
<groupId>com.biz</groupId>
<artifactId>log-collector-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
然后注入使用
@Autowired
private LogCollector logCollector;
@Test
public void testLogCollector() {
logCollector.info("Running .......");
}
运行这个测试类,就可以在控制台发现 Running … 的输出了。
有具体模块化过程后,就可以按以上过程实现具体有意义的Starter了。
第五步:分析
常见的starter会包括下面几个方面的内容:
自动配置文件,根据classpath是否存在指定的类来决定是否要执行该功能的自动配置。
- spring.factories,非常重要,指引Spring Boot找到指定的自动配置文件。
- endpoint:可以理解为一个admin,包含对服务的描述、界面、交互(业务信息的查询)
- health indicator:该starter提供的服务的健康指标
在应用程序启动过程中,Spring Boot使用SpringFactoriesLoader类加载器查找org.springframework.boot.autoconfigure.EnableAutoConfiguration关键字对应的Java配置Bean(多个配置Bean用逗号分隔)。Spring Boot会遍历在各个jar包种META-INF目录下的spring.factories文件,构建成一个配置文件链表。除了EnableAutoConfiguration关键字对应的配置文件,还有其他类型的配置文件:
org.springframework.context.ApplicationContextInitializer
org.springframework.context.ApplicationListener
org.springframework.boot.SpringApplicationRunListener
org.springframework.boot.env.PropertySourceLoader
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider
org.springframework.test.contex.TestExecutionListener
PS:Spring Boot的starter在编译时不需要依赖Spring Boot的库。但需要依赖spring-context的库,因为要用spring的注解,不是Java自带的注解。本例子中用了spring-boot的库是因为顺手了。
另外一种方式让spring boot识别我们的自动配置Bean
从上面的结果,我们指定Spring Boot 是通过spring.factories找到自动配置文件(xxxxAutoConfiguration之类的文件),其实还有一种方式,不使用spring.factories,而使用注解的方式来实现。
接着上面的例子,首先将spring.factories中的内容注释掉。
创建元注解(meta-annotation),即在src/main/java/com/biz/目录下新建EnableLogCollector.java文件。
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(LogCollectorAutoConfig.class)
@Documented
public @interface EnableLogCollector {
}
在应用模块的用@EnableDbCounting注解修饰Application启动类。
@SpringBootApplication
@EnableLogCollector
public class XxxApplication {
public static void main(String[] args) {
SpringApplication.run(XxxApplication.class, args);
}
}
启动应用程序,设置日志级别为DEBUG
由starter的用户手动触发配置,查看启动过程日志可以看出我们自己定义的注解起作用了。
如果没有spring.factories,那么在程序启动的时候Spring Boot的自动配置机制不会试图解析其他jar包下的XxxAutoConfiguration类。一般来说,@Component注解的作用范围就是在我们自己的业务模块下的Application启动类所在的目录以及各个子目录,我们自定义的Configuration类很可能不在这个包结构下,因此不会被扫描到。
@EnableLogCollector注解通过@Import(LogCollectorAutoConfig.class)找到对应的配置类,因此通过用@EnableLogCollector修饰XxxApplication,就是告诉Spring Boot在启动过程中要把LogCollectorAutoConfig加入到应用上下文中。