【问题标题】:Spring /boot, profiles, java config and bean creation order (Unexpected behaviour??)Spring /boot、profiles、java config 和 bean 创建顺序(意外行为??)
【发布时间】:2016-01-19 18:16:02
【问题描述】:

我正在开发一个 Spring Boot 应用程序。我们有每个环境的属性文件(dev、int、qa、prd 等)。至于 bean,有些需要以不同的方式创建以用于生产。所以我们有这样的配置:

@Configuration
class MyBeans {
    @Bean(name="someBean")
    @Profile("prd")
    MyBean someBeanProd() {
        ...
    }

    @Bean(name="someBean")
    MyBean someBeanDev() {
        ...
    }
}

MyBean 自动装配如下:

@Component
public class SomeService 
{
    @Autowired
    private MyBean someBean;
}

当启动应用程序时:

-Dspring.profiles.active=prd

'someBeanProd' 方法被调用(如预期的那样),并且正在加载相关的属性文件(application-prd.properties)。对于任何其他配置文件“someBeanDev”正在被调用(如预期的那样)并加载相关的属性文件。

但是,如果我如下更改配置中方法的顺序,则始终调用“someBeanDev”方法(即使活动配置文件为 prd),但正在使用正确的属性文件。

@Configuration
class MyBeans {
    @Bean(name="someBean")
    MyBean someBeanDev() {
        ...
    }

    @Bean(name="someBean")
    @Profile("prd")
    MyBean someBeanProd() {
        ...
    }
}

这是正确/预期的行为吗?无论配置文件中方法的顺序如何,我都希望 spring 创建正确的 bean。

有没有办法为一个配置文件定义一个 bean,而任何其他配置文件都应该回退到“默认”配置文件?

在不同的 Java 配置类中创建 prd bean 也不起作用。

【问题讨论】:

    标签: spring spring-boot spring-java-config spring-profiles


    【解决方案1】:

    您可以使用@Primary(不指定bean 的名称):

    @Bean
    public MyBean someBeanDev() {
        return new MyBean("dev");
    }
    
    @Primary
    @Profile("prd")
    @Bean
    public MyBean someBeanProd() {
        return new MyBean("prod");
    }
    

    在这种情况下,如果 profile 为“prd”,则两个 @Bean 方法都会被调用,但任何 @Autowired MyBean 都将只有 someBeanProd() 返回的 MyBean。 如果您还想拥有@Autowire Collection<MyBean>,这种情况会很有用。

    或使用@ConditionalOnMissingBean 和bean 名称(或带有value 属性的bean 类):

    @Configuration
    public class ConfProd {
    
        @Profile("prd")
        @Bean(name = "someBean")
        public MyBean someBeanProd() {
            return new MyBean("prod");
        }
    }
    
    @Configuration
    public class ConfDev {
    
        @ConditionalOnMissingBean(name = "someBean")
        @Bean(name = "someBean")
        public MyBean someBeanDev() {
            return new MyBean("dev");
        }
    }
    

    在这种情况下,只有一个@Bean方法被称为依赖于指定的配置文件。

    【讨论】:

    • 我尝试了 @AutoConfigureAfter 的方法,但仍然无法正常工作。
    • 抱歉,按输入太早了...感谢您的回复。我尝试了@AutoConfigureAfter 的方法,但它仍然无法正常工作。有趣的是,如果 prd 配置类在 dev 配置类之后按字母顺序排列,那么 spring 使用正确的 bean(有或没有 AutoConfigureAfter 注释)。例如: DevConfig, ProdConfig = 工作正常 DevConfig, Config = 不工作我没有尝试第一种方法,因为如果不需要,我不想创建 bean。
    • 我的行为与您的行为相同,这在 IMO 中并不简单。无论如何,我编辑了我的答案(第二种方法),这个应该可以工作。
    • 是的,使用 !prd 可以正常工作,但不符合我们的要求。理想情况下,我们需要一个“后备”bean,仅当它不是为其他活动配置文件创建时才创建(我们有多个活动配置文件)。我不明白为什么配置类中的方法顺序会影响创建的 bean。
    • 我再次更新了我的答案(第二种方法),这次它应该可以解决问题并满足您的需求。我还尝试使用 2 个单独的配置类(具有不同的类名),它具有相同的行为。
    【解决方案2】:

    我也注意到了这种行为,解决方法是将不同的配置文件 bean 保留在不同的 @Profile 注释类中(这有点麻烦,但我记得它工作正常)

    例如

    假设您的生产配置文件中有 bean1 和 bean2 的两个实现,而暂存配置文件有两个不同的实现

    你想创建 两个配置类

    @Configuration
    @Profile({"production"})
    public class ConfigProduction {
      @Bean Bean1 bean1(){ return prod impl;}]
      @Bean Bean2 bean2(){ return prod impl;}
    }
    
    @Configuration
    @Profile({"staging"})
    public class ConfigStaging {
      @Bean Bean1 bean1(){ return staging impl;}]
      @Bean Bean2 bean2(){ return staging impl;}
    }
    

    在您的默认 application.properties 将生产(或任何您喜欢的)设置为活动配置文件

    spring.profiles.active=production,具有类似“后备”的行为

    试试看

    【讨论】:

      猜你喜欢
      • 2019-12-25
      • 2019-04-03
      • 1970-01-01
      • 2016-07-05
      • 1970-01-01
      • 2018-06-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多