集成测试Spring应用程序要求创建小的专用配置片段,并在应用程序正常运行或测试期间组装它们。 即使在后一种情况下,也可以在不同的测试中组装不同的片段。
但是,这种做法无法处理我要在两个不同环境中使用应用程序的用例。 例如,在本地计算机上进行开发时,我可能想在部署的环境中使用JNDI数据源,并使用直接连接。 不可能组合不同的片段组合,因为我想在两种情况下都运行该应用程序,而不是对其进行测试。
我唯一的要求是,默认值应使用JNDI数据源,同时激活标志-配置文件,应切换到直接连接。 在这种情况下,Pavlovian反射将是在@Configuration
类中添加一个简单条件。
@Configuration
publicclassMyConfiguration{
@Autowired
privateEnvironmentenv;
@Bean
publicDataSourcedataSource()throwsException{
if(env.acceptsProfiles("dev")){
org.apache.tomcat.jdbc.pool.DataSourcedataSource=neworg.apache.tomcat.jdbc.pool.DataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:file:~/conditional");
dataSource.setUsername("sa");
returndataSource;
}
JndiDataSourceLookupdataSourceLookup=newJndiDataSourceLookup();
returndataSourceLookup.getDataSource("java:comp/env/jdbc/conditional");
}
}
开始使用这种流控制语句是结束的开始,因为它将导致将来添加更多的控制流语句,这又将导致混乱的意大利面配置,最终导致无法维护的应用程序。
Spring Boot提供了一个不错的替代方案,可以使用@ConditionalXXX
注释的不同@ConditionalXXX
来处理此用例。 在工作时使用它们具有以下优点:易于使用,易读且受限制。 尽管后者似乎是一个缺点,但这是最大的恕我直言(与Maven插件不同)。 代码功能强大,强大的功能必须承担巨大的责任,这在项目的过程中几乎是不可能的,因为项目的截止日期和上级领导的压力。 这是我的一位同事提倡XML优于JavaConfig的主要原因:使用XML,您可以确保在项目运行过程中不会有任何滥用。
但是,让我们停止哲学,回到@ConditionalXXX
批注。 基本上,将这样的注释放在@Bean
方法上将调用此方法,并根据专用条件将Bean放入工厂。 它们很多,下面是一些重要的:
- 取决于Java版本,新旧-
@ConditionalOnJava
- 取决于工厂中存在的
@ConditionalOnBean
,反之,取决于不存在的bean名称-@ConditionalOnMissingBean
- 依赖于类路径中存在的类-
@ConditionalOnClass
及其相对的@ConditionalOnMissingClass
- 无论是Web应用程序-
@ConditionalOnWebApplication
和@ConditionalOnNotWebApplication
- 等等
请注意,可以在Spring Boot的org.springframework.boot.autoconfigure.condition软件包中浏览现有条件的整个列表。
有了这些信息,我们可以将上面的代码片段迁移到更可靠的实现中:
@Configuration
publicclassMyConfiguration{
@Bean
@Profile("dev")
publicDataSourcedataSource()throwsException{
org.apache.tomcat.jdbc.pool.DataSourcedataSource=neworg.apache.tomcat.jdbc.pool.DataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:file:~/localisatordb");
dataSource.setUsername("sa");
returndataSource;
}
@Bean
@ConditionalOnMissingBean(DataSource.class)
publicDataSourcefakeDataSource(){
JndiDataSourceLookupdataSourceLookup=newJndiDataSourceLookup();
returndataSourceLookup.getDataSource("java:comp/env/jdbc/conditional");
}
}
现在,配置被巧妙地分为两个不同的方法,第一个方法仅在dev
配置文件处于活动状态时才被调用,而第二个方法是在第一个方法未被调用时(即dev
配置文件处于不活动状态时)被调用。
最后,该功能的最好之处在于它易于扩展,因为它仅取决于@Conditional
批注和Condition
接口(它们是Spring固有的一部分,而不是Spring Boot的一部分)。
这是一个Maven / IntelliJ格式的简单示例供您使用。 玩得开心!
翻译自: https://blog.frankel.ch/avoid-conditional-logic-in-configuration/