admin管理员组文章数量:1123412
I have a Spring webapp on Tomcat with two implementations of an interface. I want to be able to decide at configuration time (not necessarily at runtime) which one to instance, and I am using @Profile
.
public interface ClienteFarmacia {}
@Component
@Profile("farmaciaDb")
public class ClienteFarmaciaDbImpl implements ClienteFarmacia {}
@Component
@Profile("farmaciaWs")
public class ClienteFarmaciaWsImpl implements ClienteFarmacia {}
If I enable the profile by setting an environment variable (export spring_profiles_active=farmaciaDb
) it works as expected.
But as I already have a configuration properties file and I would like to centralize all of it there, I am trying to activate the profile programmatically. I have a @Component
that in its @PostConstruct
loads that properties, and in it I use the ConfigurableEnvironment
. The logic works and is executed before the ClienteFarmacia
instance is created, but anyway the instantiation fails because Spring does not find which instance to use.
The configuration class:
@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] [main] DEBUG e.s.d.e.e.p.config.Configuracion.init(123) - Asignado activeProfile farmaciaDb
[2025-01-10T14:59:52.154+01:00] [main] WARN o.s.w.c.s.AnnotationConfigWebApplicationContext.refresh(599) - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'autenticacionController': Unsatisfied dependency expressed through field 'idp'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'idp': Unsatisfied dependency expressed through field 'clienteFarmacia'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'es.ssib.dtic.ereceta.ehdsi.portal.farmacia.ClienteFarmacia' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
[2025-01-10T14:59:52.156+01:00] [main] INFO o.s.o.j.LocalEntityManagerFactoryBean.destroy(651) - Closing JPA EntityManagerFactory for persistence unit 'PortalEhdsiDB'
[2025-01-10T14:59:52.160+01:00] [main] ERROR o.s.web.servlet.DispatcherServlet.initServletBean(534) - Context initialization failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'autenticacionController': Unsatisfied dependency expressed through field 'idp'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'idp': Unsatisfied dependency expressed through field 'clienteFarmacia'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'es.ssib.dtic.ereceta.ehdsi.portal.farmacia.ClienteFarmacia' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:713)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:693)
How can I get what I want?
I have a Spring webapp on Tomcat with two implementations of an interface. I want to be able to decide at configuration time (not necessarily at runtime) which one to instance, and I am using @Profile
.
public interface ClienteFarmacia {}
@Component
@Profile("farmaciaDb")
public class ClienteFarmaciaDbImpl implements ClienteFarmacia {}
@Component
@Profile("farmaciaWs")
public class ClienteFarmaciaWsImpl implements ClienteFarmacia {}
If I enable the profile by setting an environment variable (export spring_profiles_active=farmaciaDb
) it works as expected.
But as I already have a configuration properties file and I would like to centralize all of it there, I am trying to activate the profile programmatically. I have a @Component
that in its @PostConstruct
loads that properties, and in it I use the ConfigurableEnvironment
. The logic works and is executed before the ClienteFarmacia
instance is created, but anyway the instantiation fails because Spring does not find which instance to use.
The configuration class:
@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] [main] DEBUG e.s.d.e.e.p.config.Configuracion.init(123) - Asignado activeProfile farmaciaDb
[2025-01-10T14:59:52.154+01:00] [main] WARN o.s.w.c.s.AnnotationConfigWebApplicationContext.refresh(599) - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'autenticacionController': Unsatisfied dependency expressed through field 'idp'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'idp': Unsatisfied dependency expressed through field 'clienteFarmacia'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'es.ssib.dtic.ereceta.ehdsi.portal.farmacia.ClienteFarmacia' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
[2025-01-10T14:59:52.156+01:00] [main] INFO o.s.o.j.LocalEntityManagerFactoryBean.destroy(651) - Closing JPA EntityManagerFactory for persistence unit 'PortalEhdsiDB'
[2025-01-10T14:59:52.160+01:00] [main] ERROR o.s.web.servlet.DispatcherServlet.initServletBean(534) - Context initialization failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'autenticacionController': Unsatisfied dependency expressed through field 'idp'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'idp': Unsatisfied dependency expressed through field 'clienteFarmacia'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'es.ssib.dtic.ereceta.ehdsi.portal.farmacia.ClienteFarmacia' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:713)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:693)
How can I get what I want?
Share Improve this question asked 12 hours ago SJuan76SJuan76 24.8k6 gold badges51 silver badges92 bronze badges2 Answers
Reset to default 1Can you try the following solution?
- Instead of setting the profile within a @PostConstruct method, you should configure the profiles early in the application's startup process. The most common approach is to configure the active profile programmatically before the Spring context refreshes.
- You can use an ApplicationContextInitializer to set the active profiles before the Spring context is initialized.
Here's how you can implement it:
Create an ApplicationContextInitializer Implementation
This initializer allows you to set the active profiles before Spring starts scanning for beans.
public class ProfileApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
String farmaciaClientType = System.getenv("FARMACIA_CLIENT_TYPE"); // Or load it from a config file
switch (farmaciaClientType) {
case "BD":
applicationContext.getEnvironment().setActiveProfiles("farmaciaDb");
break;
case "WS":
applicationContext.getEnvironment().setActiveProfiles("farmaciaWs");
break;
default:
throw new RuntimeException("Invalid farmacia client type");
}
}
}
Register the Initializer in web.xml (or Java Config)
If you're using web.xml, you can register the initializer like this:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>com.example.ProfileApplicationContextInitializer</param-value>
</context-param>
Alternatively, if you're using a Spring Boot application or Java-based configuration, you can add the initializer to your application class:
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MyApplication.class);
app.addInitializers(new ProfileApplicationContextInitializer());
app.run(args);
}
}
Profile-Scoped Beans
Make sure that the beans (ClienteFarmaciaDbImpl and ClienteFarmaciaWsImpl) are defined with the correct profiles:
@Component
@Profile("farmaciaDb")
public class ClienteFarmaciaDbImpl implements ClienteFarmacia {}
@Component
@Profile("farmaciaWs")
public class ClienteFarmaciaWsImpl implements ClienteFarmacia {}
I think you're failing to take advantage of some of the tools Spring Boot offers to manage some of this stuff for you. @Configuration and @AutoConfiguration classes are designed to allow you to conditionally create different beans to establish the logic you want based on your environment to. In your case you could create something like:
@AutoConfiguration
public class ClienteFarmaciaAutoConfiguration {
@Bean
@Profile("farmaciaDb")
public ClienteFarmacia clienteFarmacia() {
return new ClienteFarmaciaDbImpl();
}
@Bean
@Profile("farmaciaWs")
public ClienteFarmacia clienteFarmacia() {
return new ClienteFarmaciaWsImpl();
}
}
It would also be a best practice to mark one of these as @Primary incase both profiles are ever set.
If you can, its likely better to use ConfigurationProperties to control this behavior rather than using profiles. To do so, you can replace the @Profile annotation with @ConditionalOnProperty and the appropriate values.
Lastly, note that you will need to ensure your project has done all of the other setup needed on your main class to use Spring Boots Configurations. There are plenty of online articles on how to do so, its one of the core basic concepts Spring Boot offers
本文标签: tomcatProblem activating Spring profile through ConfigurableEnvirnomentStack Overflow
版权声明:本文标题:tomcat - Problem activating Spring profile through ConfigurableEnvirnoment - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736563006a1944669.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论