避免在@Configuration中使用条件逻辑

集成测试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/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值