1. 概述
Spring Boot为开发人员提供了大多数流行的开源项目的启动器,但我们不仅限于此。
我们也可以编写自己的自定义启动器。 如果想为我们的组织提供一个内部库,并且将它在Spring Boot上下文中使用,那么为它编写一个启动器也许是一个好的习惯。
这些启动器使开发人员能够避免冗长的配置并快速启动他们的开发。但是,由于隐藏了在后台发生的很多事情,有时候很难理解注释或只是在pom.xml中包含些依赖项就能够实现这么多功能。
在本文中,我们将揭开Spring Boot的神秘面纱,看看幕后发生了什么。然后我们将使用这些概念为我们自己的自定义库创建一个启动器。
2. 揭开Spring Boot自动配置的神秘面纱
2.1 自动配置类
当Spring Boot启动时,它会在类路径中查找名为spring.factories的文件。该文件位于META-INF目录中。让我们看一下spring-boot-autoconfigure项目中这个文件的片段:
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
此文件将名称映射到Spring Boot将尝试运行的不同配置类。因此,根据这个片段,Spring Boot将尝试运行RabbitMQ,Cassandra,MongoDB和Hibernate的所有配置类。
这些类是否实际运行将取决于类路径上是否存在依赖类。例如,如果在类路径中找到MongoDB的类,则将运行MongoAutoConfiguration,并初始化所有与mongo相关的bean。
此条件初始化由@ConditionalOnClass注释启用。让我们看一下MongoAutoConfiguration类的代码片段,看看它的用法:
@Configuration
@ConditionalOnClass(MongoClient.class)
@EnableConfigurationProperties(MongoProperties.class)
@ConditionalOnMissingBean(type = "org.springframework.data.mongodb.MongoDbFactory")
public class MongoAutoConfiguration {
// configuration code
}
现在如果MongoClient在类路径中可用 - 这个配置类将运行,使用默认配置设置初始化的MongoClient来填充Spring bean工厂。
2.2 application.properties文件中的自定义属性
Spring Boot使用一些预先配置的默认值初始化bean。要覆盖这些默认值,我们通常会在application.properties文件中使用某个特定名称声明它们。Spring Boot容器会自动获取这些属性。
让我们看看它是如何工作的。
在MongoAutoConfiguration的代码片段中,使用MongoProperties类声明@EnableConfigurationProperties注释,该类充当自定义属性的容器:
@ConfigurationProperties(prefix = "spring.data.mongodb")
public class MongoProperties {
private String host;
// other fields with standard getters and setters
}
前缀加上字段名称可以在application.properties文件中创建属性的名称。因此,要设置MongoDB 的主机,我们只需要在属性文件中编写以下内容:
spring.data.mongodb.host = localhost
同样,可以使用属性文件设置类中其他字段的值。
3. 创建自定义启动器
根据第2节中的概念,要创建自定义启动器,我们需要编写以下组件:
- 我们库的自动配置类以及自定义配置的属性类。
- 一个启动程序pom,用于引入库和autoconfigure项目的依赖项。
为了演示,我们创建了一个简单的greeter库,它将作为配置参数接收一天中不同时间的问候消息并输出问候应答消息。我们还将创建一个示例Spring Boot应用程序来演示我们的autoconfigure和starter模块的用法。
3.1 自动配置模块
我们将自动配置模块称为greeter-spring-boot-autoconfigure。该模块将有两个主要类,即GreeterProperties - 它将通过application.properties文件和GreeterAutoConfiguartion设置自定义属性,这将为greeter库创建bean 。
让我们看看这两个类的代码:
@ConfigurationProperties(prefix = "peterwanghao.samples.greeter")
public class GreeterProperties {
private String userName;
private String morningMessage;
private String afternoonMessage;
private String eveningMessage;
private String nightMessage;
// standard getters and setters
}
@Configuration
@ConditionalOnClass(Greeter.class)
@EnableConfigurationProperties(GreeterProperties.class)
public class GreeterAutoConfiguration {
@Autowired
private GreeterProperties greeterProperties;
@Bean
@ConditionalOnMissingBean
public GreetingConfig greeterConfig() {
String userName = greeterProperties.getUserName() == null
? System.getProperty("user.name")
: greeterProperties.getUserName();
// ..
GreetingConfig greetingConfig = new GreetingConfig();
greetingConfig.put(USER_NAME, userName);
// ...
return greetingConfig;
}
@Bean
@ConditionalOnMissingBean
public Greeter greeter(GreetingConfig greetingConfig) {
return new Greeter(greetingConfig);
}
}
我们还需要在src/main/resources/META-INF目录中添加一个spring.factories文件,其中包含以下内容:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.peterwanghao.samples.greeter.autoconfigure.GreeterAutoConfiguration
在应用程序启动时,如果类路径中存在类Greeter,则将运行GreeterAutoConfiguration类。如果成功运行,它将通过GreeterProperties类读取属性,使用GreeterConfig和Greeter bean 填充Spring应用程序上下文。
@ConditionalOnMissingBean注释将确保,如果他们不存在,这些bean才会创建。这使开发人员可以通过在其中一个@Configuration类中定义自己配置的bean来完全覆盖自动配置的bean 。
3.2 创建pom.xml
现在让我们创建一个启动程序pom,它将为自动配置模块和greeter库带来依赖关系。
根据命名约定,所有不由核心Spring Boot团队管理的启动器应该以库名称开头,后面跟后缀-spring-boot-starter。所以我们将把我们的启动器称为greeter-spring-boot-starter:
4.0.0
com.peterwanghao.samples.springboot
spring-boot-custom-starter
0.0.1-SNAPSHOT
greeter-spring-boot-starter
greeter-spring-boot-starter
org.springframework.boot
spring-boot-starter
${spring-boot.version}
com.peterwanghao.samples.springboot
greeter-spring-boot-autoconfigure
${project.version}
com.peterwanghao.samples.springboot
greeter-library
${greeter.version}
UTF-8
0.0.1-SNAPSHOT
2.1.1.RELEASE
3.3 使用Starter
让我们创建一个使用启动器的应用greeter-spring-boot-sample-app。在pom.xml中,我们需要将其添加为依赖项:
com.peterwanghao.samples.springboot
greeter-spring-boot-starter
${greeter-starter.version}
Spring Boot将自动配置所有内容,我们将准备好注入和使用Greeter bean。
让我们通过使用peterwanghao.samples.greeter前缀在application.properties文件中定义GreeterProperties的一些属性值来改变它们的一些默认值:
peterwanghao.samples.greeter.userName=Peter
peterwanghao.samples.greeter.afternoonMessage=Woha\Afternoon
最后,让我们在我们的应用程序中使用Greeter bean:
@SpringBootApplication
public class GreeterSampleApplication implements CommandLineRunner {
@Autowired
private Greeter greeter;
public static void main(String[] args) {
SpringApplication.run(GreeterSampleApplication.class, args);
}
public void run(String... args) throws Exception {
String message = greeter.greet();
System.out.println(message);
}
}
4. 结论
在这个简单教程中,我们专注于创建自定义Spring Boot启动器,以及这些启动器如何与自动配置机制一起工作 - 通过后台工作以消除大量手动配置。
我们在本文中创建的完整源代码都可以在GitHub上找到。