通过 ConfigurableEnvirnoment 激活 Spring 配置文件时出现问题

问题描述 投票:0回答:1

我在 Tomcat 上有一个 Spring Web 应用程序,其中有两个接口的实现。我希望能够在配置时(不一定在运行时)决定要实例化哪一个,并且我正在使用

@Profile

public interface ClienteFarmacia {}

@Component
@Profile("farmaciaDb")
public class ClienteFarmaciaDbImpl implements ClienteFarmacia {}

@Component
@Profile("farmaciaWs")
public class ClienteFarmaciaWsImpl implements ClienteFarmacia {}

如果我通过设置环境变量 (

export spring_profiles_active=farmaciaDb
) 来启用配置文件,它会按预期工作。

但是由于我已经有了一个配置属性文件,并且我想将所有这些文件集中在那里,所以我尝试以编程方式激活配置文件。我有一个

@Component
,它在
@PostConstruct
中加载该属性,并且在其中我使用
ConfigurableEnvironment
。该逻辑工作并在创建
ClienteFarmacia
实例之前执行,但无论如何实例化都会失败,因为 Spring 找不到要使用的实例。

配置类:

@Component
public class Configuracion {
    @Autowired
    private ConfigurableEnvironment env;

    @PostConstruct
    void init() {
       [... Load data]
       switch (farmaciaClientType) {
        case "BD":
            log.debug("Asignado activeProfile farmaciaDb");
            this.env.setActiveProfiles("farmaciaDb");
            break;
        case "WS":
            log.debug("Asignado activeProfile farmaciaWs");
            this.env.setActiveProfiles("farmaciaWs");
            break;
        default:
            log.error("farmacia.tipoConsulta es " + tipoConsultaFarmacia + ", valores válidos BD o WS");
            throw new RuntimeException("Error cargando configuración");
        }
    }

[2025-01-10T14:59:52.145+01:00] [主要] 调试 e.s.d.e.e.p.config.Configuracion.init(123) - Asignado activeProfile farmaciaDb
[2025-01-10T14:59:52.154+01:00] [主要] 警告 o.s.w.c.s.AnnotationConfigWebApplicationContext.refresh(599) - 上下文初始化期间遇到异常 - 取消刷新尝试:org.springframework.beans.factory.UnsatisfiedDependencyException:创建名称为“autenticacionController”的 bean 时出错:通过字段“idp”表达的依赖关系不满足;嵌套异常是 org.springframework.beans.factory.UnsatisfiedDependencyException:创建名称为“idp”的 bean 时出错:通过字段“clienteFarmacia”表达的依赖关系不满足;嵌套异常是 org.springframework.beans.factory.NoSuchBeanDefinitionException:没有类型为“es.ssib.dtic.ereceta.ehdsi.portal.farmacia.ClienteFarmacia”的合格 bean 可用:预计至少有 1 个有资格作为自动装配候选者的 bean。依赖注解:{@org.springframework.beans.factory.annotation.Autowired(required=true)}
[2025-01-10T14:59:52.156+01:00] [主要] 信息 o.s.o.j.LocalEntityManagerFactoryBean.destroy(651) - 关闭持久性单元“PortalEhdsiDB”的 JPA EntityManagerFactory
[2025-01-10T14:59:52.160+01:00] [主要] 错误 o.s.web.servlet.DispatcherServlet.initServletBean(534) - 上下文初始化失败
org.springframework.beans.factory.UnsatisfiedDependencyException:创建名称为“autenticacionController”的bean时出错:通过字段“idp”表达的依赖关系不满足;嵌套异常是 org.springframework.beans.factory.UnsatisfiedDependencyException:创建名称为“idp”的 bean 时出错:通过字段“clienteFarmacia”表达的依赖关系不满足;嵌套异常是 org.springframework.beans.factory.NoSuchBeanDefinitionException:没有类型为“es.ssib.dtic.ereceta.ehdsi.portal.farmacia.ClienteFarmacia”的合格 bean 可用:预计至少有 1 个有资格作为自动装配候选者的 bean。依赖注释:{@org.springframework.beans.factory.annotation.Autowired(required=true)}
在 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:713)
在org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor $AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:693)

我怎样才能得到我想要的东西?

spring tomcat spring-profiles
1个回答
0
投票

我认为你没有利用 Spring Boot 提供的一些工具来为你管理一些东西。 @Configuration 和 @AutoConfiguration 类旨在允许您有条件地创建不同的 bean,以根据您的环境建立您想要的逻辑。在你的情况下,你可以创建类似的东西:

@AutoConfiguration
public class ClienteFarmaciaAutoConfiguration {
    @Bean
    @Profile("farmaciaDb")
    public ClienteFarmacia clienteFarmacia() {
        return new ClienteFarmaciaDbImpl();
    }

    @Bean
    @Profile("farmaciaWs")
    public ClienteFarmacia clienteFarmacia() {
        return new ClienteFarmaciaWsImpl();
    } 
}

最好将其中一个标记为@Primary,以防两个配置文件都已设置。

如果可以的话,使用 ConfigurationProperties 来控制此行为可能比使用配置文件更好。为此,您可以将 @Profile 注释替换为 @ConditionalOnProperty 和适当的值。

最后,请注意,您需要确保您的项目已完成主类上使用 Spring Boots 配置所需的所有其他设置。网上有很多关于如何做到这一点的文章,这是 Spring Boot 提供的核心基本概念之一

© www.soinside.com 2019 - 2024. All rights reserved.