I have two different beans for the same class with different configurations depending on the given profile.
#Bean
#Profile("!local")
public VaultPropertySource vaultPropertySource(ConfigurableApplicationContext context)
#Bean
#Profile("local")
public VaultPropertySource vaultPropertySourceLocal(ConfigurableApplicationContext context)
I have another bean that depends on VaultPropertySource instance.
#Component
#RequiredArgsConstructor
#DependsOn({"vaultPropertySource"})
public class VaultPropertyReader {
private final VaultPropertySource vaultPropertySource;
The problem is bean names are different and it only works on the first instance. How can I make it work on both profiles? Can I make it depend on the bean class instead of bean name?
Separate the profiles not on the bean but on the configuration class:
#Configuration
#Profile("!local")
class VaultConfiguration {
#Bean
public VaultPropertySource vaultPropertySource(ConfigurableApplicationContext context) {
// return real PropertySource
}
}
#Configuration
#Profile("local")
class LocalVaultConfiguration {
#Bean
public VaultPropertySource vaultPropertySource(ConfigurableApplicationContext context) {
// return local PropertySource
}
}
That probably helps.
I have this project hierarchy:
A SpringConfiguration.java file with one Bean (SoapServiceBean).
A LoggerUtilsConfiguration.java with two beans (ConfigManager and LoggerManager).
SpringConfiguration imports LoggerUtilsConfigueration with an #Import.
The code:
#Configuration
#Import({com.myApp.LoggerUtilsConfiguration.class})
public class SpringConfiguration {
#Lazy
#Bean(name = "soapServiceBean")
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public SoapServiceBean soapServiceBeanInit(
#Qualifier("configManager") ConfigManager configManager ,
#Qualifier("loggerManager") LoggerManager loggerManager)
throws ServiceException, SystemException {
SoapServiceBean service = new SoapServiceBean();
service.setConfigManager(configManager);
service.setLoggerManager(loggerManager);
return service;
}
}
#Configuration
public class LoggerUtilsConfiguration {
#Bean(name = "configManager")
#Scope(BeanDefinition.SINGLETON)
public ConfigManager configManagerInit() {
ConfigManager cManager = new ConfigManager();
return cManager;
}
#Bean(name = "loggerManager")
#Scope(BeanDefinition.SINGLETON)
public LoggerManager loggerManagerInit() {
LoggerManager cManager = new LoggerManager();
return cManager;
}
}
My problema is that, "configManager" is a valid bean, but loggerManager throws this Exception:
No qualifying bean of type [com.myApp.LoggerManager] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency.
Dependency annotations: {#org.springframework.beans.factory.annotation.Qualifier(value=loggerManager)}
Is very Strange, because If I copy the loggerManager Bean method into the main #Configuration class, the app starts with no problem and loggerManager is started with no problem.
"LoggerUtilsConfiguration" is not part of my App, is a Maven dependency external jar from another dev team. I have decompiled it and I cannot see anything strange, "configManager" and "loggerManager" has the same annotations with the same values except the bean name.
Any idea?
Solved.
My problem is the WebSphere, that store an old version of the third party JAR.
\was\wasprofiles\wp_profile80\installedApps\GUUPZN00Cell\MY-APP.ear\lib\LOGGER-LIB-1.0.0.jar
\was\wasprofiles\wp_profile80\installedApps\GUUPZN00Cell\MY-APP.ear\lib\LOGGER-LIB-1.0.1.jar
The version "1.0.0" LOGGER-LIB doesn't contains the bean "loggerManager" and WebSphere is loading this version of the library.
It seems that the file was blocked when websphere try to delete it. I had to stop the server to delete it properly.
If the 2 managers are singletons you can #Autowired them in.
If there is an existing bean called loggerManager of a different type then it wouldn't find yours, but it depends on how your classpath is set up.
#Configuration
#Import({com.myApp.LoggerUtilsConfiguration.class})
public class SpringConfiguration {
#Autowired
ConfigManager configManager;
#Autowired
LoggerManager loggerManager;
#Lazy
#Bean(name = "soapServiceBean")
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public SoapServiceBean soapServiceBeanInit()
throws ServiceException, SystemException {
SoapServiceBean service = new SoapServiceBean();
service.setConfigManager(configManager);
service.setLoggerManager(loggerManager);
return service;
}
}
Try to use #DependsOn:
#Lazy
#Bean(name = "soapServiceBean")
#DependsOn({ "configManager", "loggerManager" })
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public SoapServiceBean soapServiceBeanInit(
#Qualifier("configManager") ConfigManager configManager ,
#Qualifier("loggerManager") LoggerManager loggerManager)
throws ServiceException, SystemException {
SoapServiceBean service = new SoapServiceBean();
service.setConfigManager(configManager);
service.setLoggerManager(loggerManager);
return service;
}
Try providing autowire annotation to properly enable constructor injection like :
#Configuration
#Import({com.myApp.LoggerUtilsConfiguration.class})
public class SpringConfiguration {
#Lazy
#Autowired
#Bean(name = "soapServiceBean")
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public SoapServiceBean soapServiceBeanInit(
#Qualifier("configManager") ConfigManager configManager ,
#Qualifier("loggerManager") LoggerManager loggerManager)
throws ServiceException, SystemException {
SoapServiceBean service = new SoapServiceBean();
service.setConfigManager(configManager);
service.setLoggerManager(loggerManager);
return service;
}
}
The #Qualifier annotation is used to resolve the bean based on names while the #Autowired annotation provides constructor injection of beans. The #Bean annotation should support constructor injection without the need for #Autowired
When using a Java Config with Spring is the best practice to wire values as a field:
#Configuration
public class ApplicationConfig {
#Value("${property}")
private String property;
#Bean
Foo foo() {
return new Foo(property);
}
}
Or as a bean parameter:
#Configuration
public class ApplicationConfig {
#Bean
Foo foo(#Value("${property}") property) {
return new Foo(property);
}
}
I believe its the latter but I don't see the specific recommendation in the Spring documentation.
We can externalize properties using <context:property-placeholder> and we can override the Spring bean properties by configuring <context:property-override> as follows:
<context:property-placeholder location="classpath:application.properties"/>
<context:property-override location="classpath:override.properties"/>
I want to move my XML config to JavaConfig.
#Configuration
#ComponentScan
#PropertySource("classpath:application.properties")
public class AppConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
But how to configure my override properties using Annotation?
PS:
I have a bean say MyBean as follows:
#Component
public class MyBean {
#Value("${someProp}")
private String someProp;
}
In my application.properties I have
someProp=TestValue
and in my override.properties i am overriding someProp value as
myBean.someProp=RealValue
No, It isn't.
But you could create a bean of type PropertyOverrideConfigurer in the configuration class whit the same result.
Update
For example:
#Bean public static PropertyOverrideConfigurer propertyOverrideConfigurer() {
PropertyOverrideConfigurer overrideConfigurer = new PropertyOverrideConfigurer();
overrideConfigurer.setLocation(new ClassPathResource("override.properties"));
return overrideConfigurer;
}
Note the static modifier, this is because BFPP should be instantiated early in the container lifecycle.
see http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Bean.html for more info.
I have the following configuration bean for a non web app
#Configuration
public class MyBeans {
#Bean
#Scope(value="prototype")
MyObject myObject() {
return new MyObjectImpl();
}
}
On the other side I have my class
public class MyCommand implements Command {
#Autowired
private MyObject myObject;
[...]
}
How can I make myCommand be autowired with the configuration in MyBeans without using XML so I can inject mocks in my other test classes?
Thanks a lot in advance.
With XML-based configuration you'd use the ContextConfiguration annotation. However, the ContextConfiguration annotation doesn't appear to work with Java Config. That means that you have to fall back on configuring your application context in the test initialization.
Assuming JUnit4:
#RunWith(SpringJUnit4ClassRunner.class)
public class MyTest{
private ApplicationContext applicationContext;
#Before
public void init(){
this.applicationContext =
new AnnotationConfigApplicationContext(MyBeans.class);
//not necessary if MyBeans defines a bean for MyCommand
//necessary if you need MyCommand - must be annotated #Component
this.applicationContext.scan("package.where.mycommand.is.located");
this.applicationContext.refresh();
//get any beans you need for your tests here
//and set them to private fields
}
#Test
public void fooTest(){
assertTrue(true);
}
}