共计 4263 个字符,预计需要花费 11 分钟才能阅读完成。
本文首发于个人网站,原文地址:http://www.javaadu.online/?p=535,如需转载,请注明出处
在学习 Spring Boot 的过程中,接触最多的就是 starter。可以认为 starter 是一种服务——使得使用某个功能的开发者不需要关注各种依赖库的处理,不需要具体的配置信息,由 Spring Boot 自动通过 classpath 路径下的类发现需要的 Bean,并织入 bean。举个例子,spring-boot-starter-jdbc这个 starter 的存在,使得我们只需要在 BookPubApplication 下用 @Autowired
引入 DataSource 的 bean 就可以,Spring Boot 会自动创建 DataSource 的实例。
这里我们会用一个不太规范的 starter 展示 Spring Boot 的自动配置的运行原理。Spring Boot 的自动配置、Command-line Runner 一文中曾利用 StartupRunner 类在程序运行启动后首先查询数据库中书的数目,现在换个需求:在系统启动后打印各个实体的数量。
How Do
- 新建一个模块db-count-starter,然后修改 db-count-starter 模块下的 pom 文件,增加对应的库。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<!-- version 继承父模块的 -->
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>1.9.3.RELEASE</version>
</dependency></dependencies>
- 新建包结构com/test/bookpubstarter/dbcount,然后新建 DbCountRunner 类,实现 CommandLineRunner 接口,在 run 方法中输出每个实体的数量。
package com.test.bookpubstarter.dbcount;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.data.repository.CrudRepository;
import java.util.Collection;
public class DbCountRunner implements CommandLineRunner {protected final Logger logger = LoggerFactory.getLogger(DbCountRunner.class);
private Collection<CrudRepository> repositories;
public DbCountRunner(Collection<CrudRepository> repositories) {this.repositories = repositories;}
@Override
public void run(String... strings) throws Exception {
repositories.forEach(crudRepository -> {
logger.info(String.format("%s has %s entries",
getRepositoryName(crudRepository.getClass()),
crudRepository.count()));
});
}
private static String getRepositoryName(Class crudRepositoryClass) {for (Class repositoryInterface : crudRepositoryClass.getInterfaces()) {if (repositoryInterface.getName().startsWith("com.test.bookpub.repository")) {return repositoryInterface.getSimpleName();
}
}
return "UnknownRepository";
}
}
- 增加自动配置文件DbCountAutoConfiguration
package com.test.bookpubstarter.dbcount;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.repository.CrudRepository;
import java.util.Collection;
@Configuration
public class DbCountAutoConfiguration {
@Bean
public DbCountRunner dbCountRunner(Collection<CrudRepository> repositories) {return new DbCountRunner(repositories);
}
}
- 在 src/main/resources 目录下新建 META-INF 文件夹,然后新建 spring.factories 文件,这个文件用于告诉 Spring Boot 去找指定的自动配置文件,因此它的内容是
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.test.bookpubstarter.dbcount.DbCountAutoConfiguration
- 在之前的程序基础上,在顶层 pom 文件中增加 starter 的依赖
<dependency>
<groupId>com.test</groupId>
<artifactId>db-count-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
- 把 StartupRunner 相关的注释掉,然后在 main 函数上右键Run BookPubApplication.main(…),可以看出我们编写的 starter 被主程序使用了。
分析
正规的 starter 是一个独立的工程,然后在 maven 中新仓库注册发布,其他开发人员就可以使用你的 starter 了。
常见的 starter 会包括下面几个方面的内容:
- 自动配置文件,根据 classpath 是否存在指定的类来决定是否要执行该功能的自动配置。
- spring.factories,非常重要,指导 Spring Boot 找到指定的自动配置文件。
- endpoint:可以理解为一个 admin,包含对服务的描述、界面、交互(业务信息的查询)
- health indicator:该 starter 提供的服务的健康指标
在应用程序启动过程中,Spring Boot 使用 SpringFactoriesLoader 类加载器查找 org.springframework.boot.autoconfigure.EnableAutoConfiguration 关键字对应的 Java 配置文件。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
Spring Boot 的 starter 在编译时不需要依赖 Spring Boot 的库。这个例子中依赖 spring boot 并不是因为自动配置要用 spring boot,而仅仅是因为需要实现 CommandLineRunner 接口。
两个需要注意的点
- @ConditionalOnMissingBean的作用是:只有对应的 ban 在系统中都没有被创建,它修饰的初始化代码块才会执行,用户自己手动创建的 bean 优先;
-
Spring Boot starter 如何找到自动配置文件(xxxxAutoConfiguration 之类的文件)?
- spring.factories:由 Spring Boot 触发 探测 classpath 目录下的类,进行自动配置;
- @Enable:有时需要由 starter 的 用户触发 * 查找自动配置文件的过程。
Spring Boot 1.x 系列
- Spring Boot 的自动配置、Command-line-Runner
- 了解 Spring Boot 的自动配置
- Spring Boot 的 @PropertySource 注解在整合 Redis 中的使用
- Spring Boot 项目中如何定制 HTTP 消息转换器
- Spring Boot 整合 Mongodb 提供 Restful 接口
- Spring 中 bean 的 scope
- Spring Boot 项目中使用事件派发器模式
- Spring Boot 提供 RESTful 接口时的错误处理实践
本号专注于后端技术、JVM 问题排查和优化、Java 面试题、个人成长和自我管理等主题,为读者提供一线开发者的工作和成长经验,期待你能在这里有所收获。