我在 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 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 提供的核心基本概念之一