自定义Starter- SpringBoot(9)
自定义Starter
如果Spring Boot自带的入口类不能满足要求,则可以自定义Starter。自定义Starter的步骤 如下。
1.引入必要的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
2.自定义Properties类
在使用Spring官方的Starter时,可以在application.properties文件中配置参数,以覆盖默认值。在自定义Starter时,也可以根据需要来配置Properties类,以保存配置信息,见以下代码:
package com.itheima.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "spring.mystarter")
public class MyStarterProperties {
private String parameter;
public String getParameter() {
return parameter;
}
public void setParameter(String parameter) {
this.parameter = parameter;
}
}
3.定义核心服务类
每个Starter都需要有自己的功能,所以需要定义服务类,如:
package com.itheima.properties;
public class MyStarter {
private MyStarterProperties myProperties;
public MyStarter() {
}
public MyStarter(MyStarterProperties myProperties) {
this.myProperties = myProperties;
}
public String print(){
System.out.println("参数:"+myProperties.getParameter());
String result = myProperties.getParameter();
return result;
}
}
4.定义自动配置类
每个Starter —般至少有一个自动配置类,命名规则为“名字+AutoConfiguration”,如MyStarterServiceAutoConfiguration, 配置方法见以下代码:
package com.itheima.properties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties(MyStarterProperties.class)
@ConditionalOnClass(MyStarter.class)
@ConditionalOnProperty(prefix = "spring.mystarter",value = "enabled",matchIfMissing = true)
public class MyStartServiceConfiguration {
@Autowired
private MyStarterProperties myStarterProperties = new MyStarterProperties();
@Bean
@ConditionalOnMissingBean(MyStarter.class)
public MyStarter myStarterService(){
MyStarter myStarter = new MyStarter(myStarterProperties);
return myStarter;
}
}
最后,在resources文件夹下新建目录META-INF,在目录中新建spring.factories文件, 并且在spring.factories中配置AutoConfiguration,加入以下代码:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.itheima.properties.MyStartServiceConfiguration
注解详解:
使用
ConfigurationProperties:
外部化配置的注释。如果您想绑定和验证一些外部属性(例如,来自 .properties 文件),请将其添加到类定义或@Configuration类中的@Bean方法中。绑定可以通过在带注释的类上调用 setter 来执行,或者,如果正在使用@ConstructorBinding ,则通过绑定到构造函数参数来执行。请注意,与@Value相反,SpEL 表达式不会被评估,因为属性值是外部化的。
源码解释:
表示一个类声明了一个或多个@Bean方法,并且可以被 Spring 容器处理以在运行时为这些 bean 生成 bean 定义和服务请求,例如:
@Configuration
public class AppConfig {
@Bean
public MyBean myBean() {
// instantiate, configure and return bean ...
}
}
引导@Configuration类
通过AnnotationConfigApplicationContext
@Configuration类通常使用AnnotationConfigApplicationContext或其支持 Web 的变体AnnotationConfigWebApplicationContext进行引导。前者的简单示例如下:
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class);
ctx.refresh();
MyBean myBean = ctx.getBean(MyBean.class);
// use myBean ...
有关详细信息,请参阅AnnotationConfigApplicationContext javadocs,有关Servlet容器中的 Web 配置说明,请参阅AnnotationConfigWebApplicationContext 。
通过 Spring <beans> XML
作为直接针对AnnotationConfigApplicationContext注册@Configuration类的替代方法, @Configuration类可以在 Spring XML 文件中声明为普通的<bean>定义:
<beans>
<context:annotation-config/>
<bean class="com.acme.AppConfig"/>
</beans>
在上面的示例中,需要<context:annotation-config/>以启用ConfigurationClassPostProcessor和其他有助于处理@Configuration类的注释相关的后处理器。
通过组件扫描
@Configuration使用@Component进行元注释,因此@Configuration类是组件扫描的候选对象(通常使用 Spring XML 的<context:component-scan/>元素),因此也可以像任何常规@Component一样利用@Autowired / @Inject @Component 。特别是,如果存在单个构造函数,则自动装配语义将透明地应用于该构造函数:
@Configuration
public class AppConfig {
private final SomeBean someBean;
public AppConfig(SomeBean someBean) {
this.someBean = someBean;
}
// @Bean definition using "SomeBean"
}
@Configuration类不仅可以使用组件扫描进行引导,还可以使用@ComponentScan注解配置组件扫描:
@Configuration
@ComponentScan("com.acme.app.services")
public class AppConfig {
// various @Bean definitions ...
}
有关详细信息,请参阅@ComponentScan javadocs。
使用外化值
使用Environment API
可以通过将 Spring org.springframework.core.env.Environment注入@Configuration类来查找外部化的值——例如,使用@Autowired注释:
@Configuration
public class AppConfig {
@Autowired Environment env;
@Bean
public MyBean myBean() {
MyBean myBean = new MyBean();
myBean.setName(env.getProperty("bean.name"));
return myBean;
}
}
通过Environment解析的属性驻留在一个或多个“属性源”对象中, @Configuration类可以使用@PropertySource注释将属性源贡献给Environment对象:
@Configuration
@PropertySource("classpath:/com/acme/app.properties")
public class AppConfig {
@Inject Environment env;
@Bean
public MyBean myBean() {
return new MyBean(env.getProperty("bean.name"));
}
}
有关更多详细信息,请参阅Environment和@PropertySource javadocs。
使用@Value注释
可以使用@Value注释将外部化的值注入到@Configuration类中:
@Configuration
@PropertySource("classpath:/com/acme/app.properties")
public class AppConfig {
@Value("${bean.name}") String beanName;
@Bean
public MyBean myBean() {
return new MyBean(beanName);
}
}
这种方法通常与 Spring 的PropertySourcesPlaceholderConfigurer结合使用,可以通过<context:property-placeholder/>在 XML 配置中自动启用,或者通过专用的static @Bean方法在@Configuration类中显式启用(参见“关于 BeanFactoryPostProcessor-returning @Bean方法”的@Bean的 javadocs 的详细信息)。但是请注意,通常仅当您需要自定义配置(例如占位符语法等)时才需要通过static @Bean方法显式注册PropertySourcesPlaceholderConfigurer 。特别是,如果没有 bean 后处理器(例如PropertySourcesPlaceholderConfigurer )已注册作为ApplicationContext的嵌入式值解析器,Spring 将注册一个默认的嵌入式值解析器,它根据在Environment中注册的属性源解析占位符。请参阅下面有关使用@ImportResource使用 Spring XML 组合@Configuration类的部分;参见@Value javadocs;有关使用BeanFactoryPostProcessor类型(例如PropertySourcesPlaceholderConfigurer )的详细信息,请参阅@Bean javadocs。
组合@Configuration类
使用@Import注释
@Configuration类可以使用@Import注解组成,类似于<import>在 Spring XML 中的工作方式。因为@Configuration对象在容器中作为 Spring bean 进行管理,所以可以注入导入的配置——例如,通过构造函数注入:
@Configuration
public class DatabaseConfig {
@Bean
public DataSource dataSource() {
// instantiate, configure and return DataSource
}
}
@Configuration
@Import(DatabaseConfig.class)
public class AppConfig {
private final DatabaseConfig dataConfig;
public AppConfig(DatabaseConfig dataConfig) {
this.dataConfig = dataConfig;
}
@Bean
public MyBean myBean() {
// reference the dataSource() bean method
return new MyBean(dataConfig.dataSource());
}
}
现在AppConfig和导入的DatabaseConfig都可以通过仅针对 Spring 上下文注册AppConfig来引导:
new AnnotationConfigApplicationContext(AppConfig.class);
使用@Profile注释
@Configuration类可以用@Profile注释标记,以表明只有在给定的配置文件或配置文件处于活动状态时才应处理它们:
@Profile("development")
@Configuration
public class EmbeddedDatabaseConfig {
@Bean
public DataSource dataSource() {
// instantiate, configure and return embedded DataSource
}
}
@Profile("production")
@Configuration
public class ProductionDatabaseConfig {
@Bean
public DataSource dataSource() {
// instantiate, configure and return production DataSource
}
}
或者,您也可以在@Bean方法级别声明配置文件条件 - 例如,对于同一配置类中的替代 bean 变体:
@Configuration
public class ProfileDatabaseConfig {
@Bean("dataSource")
@Profile("development")
public DataSource embeddedDatabase() { ... }
@Bean("dataSource")
@Profile("production")
public DataSource productionDatabase() { ... }
}
有关更多详细信息,请参阅@Profile和org.springframework.core.env.Environment javadocs。
使用@ImportResource注解的 Spring XML
如上所述, @Configuration类可以在 Spring XML 文件中声明为常规 Spring <bean>定义。也可以使用@ImportResource注释将 Spring XML 配置文件导入@Configuration类。可以注入从 XML 导入的 Bean 定义——例如,使用@Inject注解:
@Configuration
@ImportResource("classpath:/com/acme/database-config.xml")
public class AppConfig {
@Inject DataSource dataSource; // from XML
@Bean
public MyBean myBean() {
// inject the XML-defined dataSource bean
return new MyBean(this.dataSource);
}
}
使用嵌套@Configuration类
@Configuration类可以相互嵌套,如下所示:
@Configuration
public class AppConfig {
@Inject DataSource dataSource;
@Bean
public MyBean myBean() {
return new MyBean(dataSource);
}
@Configuration
static class DatabaseConfig {
@Bean
DataSource dataSource() {
return new EmbeddedDatabaseBuilder().build();
}
}
}
当引导这样的安排时,只需要针对应用程序上下文注册AppConfig 。由于是嵌套的@Configuration类, DatabaseConfig将自动注册。当AppConfig和DatabaseConfig之间的关系已经隐式明确时,这避免了使用@Import注释的需要。
还要注意,嵌套的@Configuration类可以与@Profile注释一起使用,从而为封闭的@Configuration类提供同一个bean 的两个选项。
配置延迟初始化
默认情况下, @Bean方法将在容器引导时急切地实例化。为了避免这种情况,@ @Lazy @Configuration一起使用,以指示在类中声明的所有@Bean方法默认情况下都是惰性初始化的。请注意, @Lazy也可以用于单个@Bean方法。
测试对@Configuration类的支持
spring-test模块中可用的 Spring TestContext 框架提供了@ContextConfiguration注解,它可以接受一组组件类引用——通常是@Configuration或@Component类。
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {AppConfig.class, DatabaseConfig.class})
public class MyTests {
@Autowired MyBean myBean;
@Autowired DataSource dataSource;
@Test
public void test() {
// assertions against myBean ...
}
}
有关详细信息,请参阅TestContext 框架 参考文档。
使用@Enable注解启用内置 Spring 功能
Spring 特性,如异步方法执行、计划任务执行、注释驱动的事务管理,甚至 Spring MVC 都可以使用它们各自的“ @Enable ”注释从@Configuration类中启用和配置。有关详细信息,请参阅@EnableAsync 、 @EnableScheduling 、 @EnableTransactionManagement 、 @EnableAspectJAutoProxy和@EnableWebMvc 。
创作@Configuration类时的约束
配置类必须作为类提供(即不是作为从工厂方法返回的实例),允许通过生成的子类进行运行时增强。
配置类必须是非最终的(允许在运行时使用子类),除非proxyBeanMethods标志设置为false ,在这种情况下不需要运行时生成的子类。
配置类必须是非本地的(即不能在方法中声明)。
任何嵌套的配置类都必须声明为static 。
@Bean方法可能不会反过来创建进一步的配置类(任何此类实例都将被视为常规 bean,它们的配置注释仍然未被检测到)。
EnableConfigurationProperties:
启用对@ConfigurationProperties注释 bean 的支持。 @ConfigurationProperties bean 可以以标准方式注册(例如使用@Bean方法),或者为了方便起见,可以直接在此注释上指定。
ConditionalOnClass:
@Conditional仅在指定的类在类路径上时匹配。可以在@Configuration类上安全地指定value() ,因为在加载类之前使用 ASM 解析注释元数据。放置在@Bean方法上时需要格外小心,考虑将条件隔离在单独的Configuration类中,特别是如果方法的返回类型与target of the condition匹配。
ConditionalOnProperty:
@Conditional检查指定属性是否具有特定值。默认情况下,属性必须存在于Environment中并且不等于false 。 havingValue()和matchIfMissing()属性允许进一步自定义。
havingValue属性可用于指定属性应具有的值。
5.打包发布
在完成上面的配置后,打包生成JAR文件,然后就可以像使用官方Starter那样使用了。如果不发布到Maven中心仓库,则需要用户手动添加依赖。
6.创建用于测试Starter的项目
在创建新顼目后,如果要添加自定义的Starter依赖,则不能用添加官Starter的方法,因为 此时还未将Starter发布到Maven中心仓库。只能通过开发工具导入此依赖JAR文件(在IDEA 中,通过单击菜单栏的 FILE—>ProjectStructure—>Modules—>Dependencies,然后单击+号,选择 JARs or directories......选项添加依赖)。然后,配置 application.properties文件,加入以下参数:
spring.mystarter.parameter=buretuzi
7.使用starter
在需要使用的地方注入依赖即可,具体使用见以下代码:@Autowired
private MyStarter myStarterService;
@Test
public void hello(){
System.out.println(myStarterService.print());
}
正规的Starter是一个独立的工程,可以在Maven中的新仓库注册发布,以便幵发人员使用。
自定义Starter包括以下几个方面的内容。
- 自动配置文件:根据classpath是否存在指定的类来决定是否要执行该功能的自动配置。
- factories:指导Spring Boot找到指定的自动配置文件。
- endpoint:包含对服务的描述、界面、交互(业务信息的查询)。
- health indicator:该Starter提供的服务的健康指标。