开发组件项目时,可能需要为组件设计持久化服务支持,组件使用者可以设置 durable
参数,选择是否开启持久化服务。如果我们在组件中引入Mybatis作为ORM框架(例如 mybatis-spring-boot-starter
),使用我们组件的开发者如果不在自己的工程中配置 datasource
,那么应用启动时就会报错:
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class
Action:
Consider the following:
If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
If you have database settings to be loaded from a particular profile you may need to activate it (the profiles dev are currently active).
如果想要使其不报错,组件使用者可以在自己的应用启动类上添加注解 @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
,以排除 datasource
的自动配置。
但是,这种方法是指标不治本的。况且,如果组件使用者不想使用这个组件的持久化服务,他本来就不需要做任何数据源配置,而我们的组件把这个错误抛给使用者,这显然是不合理的。
那么,我们应该为组件做这样的设计:
durable: true
时,开启持久化服务,并要求组件使用者为项目配置数据源;durable: false
时,关闭持久化服务,此时组件使用者不需要配置数据源,并且不能抛出因数据源未配置而导致的任何错误。
先添加一个配置类:
/**
* 排除数据源自动配置
* <p>
* 当 durable 为 false 时,
* 排除 DataSourceAutoConfiguration,
* 避免未配置数据源而导致启动失败。
* </p>
*/
@Configuration
@ConditionalOnProperty(name = "durable", havingValue = "false")
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
public class DataSourceExcludeConfiguration {
}
然后在组件开关(通过注解来实现)中引入该配置:
/**
* 启用组件服务
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ImportAutoConfiguration({
MyAutoConfiguration.class,
DataSourceExcludeConfiguration.class
})
public @interface EnableMyService {
}
注意,这里必须使用 @ImportAutoConfiguration
,而不能使用 @Import
来引入 DataSourceExcludeConfiguration
。因为只有 @ImportAutoConfiguration
才能识别 @ConditionalOnProperty
(以及其他 @Conditional
注解),并根据条件进行自动配置。
最后,组件使用者在自己的启动类上添加 @EnableMyService
来启用我们的组件服务,并且通过在配置文件中配置 durable
参数来选择是否开启持久化服务。只要 durable: false
,即便没有配置数据源,应用启动时也不会报错。