Spring #Profile works on class, but not on #Bean - java

I'm unable to get #Profile to work on a #Bean, but it works fine on the #Configuration class. In my module tests I correctly get the MyServiceStub autowired in the first example, but not in the second.
Does anyone know why?
This works:
MyConfig.java
#Configuration
#Import({StubConfig.class, RealConfig.class}
public class MyConfig {}
StubConfig.java
#Profile({"featureTest", "moduleTest"})
#Configuration
public class StubConfig {
#Bean
public MyService myService() {
return new MyServiceStub();
}
}
RealConfig.java
#Profile({"!featureTest", "!moduleTest"})
#Configuration
public class RealConfig {
#Bean
public MyService myService() {
return new MyService();
}
}
But this doesn't work:
MyConfig.java
#Configuration
public class MyConfig {
#Bean
#Profile({"featureTest", "moduleTest"})
public MyService myServiceStub() {
return new MyServiceStub();
}
#Bean
#Profile({"!featureTest", "!moduleTest"})
public MyService myService() {
return new MyService();
}
}

Instead of using #Profile approach, you could try using the #Conditional to have conditional bean creation.
Or have an explicit if-stmt to check what is the activeProfile. And you can create the Bean instance depending on the activeProfile. This approach I think would mirror what could be done in Spring XML using their expression language. But the #Conditional seems better fit for you.

Related

Overriding configuration is spring

Here is my situation. I have a parent project which has a bean configuration as follows
#Configuration
public class Configuration {
#Bean
public BeanA beanA(#Autowired BeanB beanB) {
return new BeanA(beanB);
}
I want to override this configuration, because I need to override some of the definitions on BeanB.
#Configuration
public class Configuration {
#Bean
public BeanA beanA(#Autowired BeanC beanC) {
return new BeanA(beanC);
}
Where my bean of type C
public class BeanC extends BeanB { ... }
But when I run the application, I am always getting the configuration coming from the parent. Also have enabled the bean-definition-overriding
spring.main.allow-bean-definition-overriding=true
Does anyone knows how can I tell the spring container to use my bean definition instead the one that is coming from my parent project.
Thanks in advance!
You can annotate your bean with #Primary annotation (see: https://www.baeldung.com/spring-primary)
#Configuration
public class Configuration {
#Primary
#Bean
public BeanA beanA(#Autowired BeanC beanC) {
return new BeanA(beanC);
}

spring boot boostrap bean override

In my spring.factories I have such a definition:
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
MyBootstrapConfiguration
In MyBootstrapConfiguration I have :
#Configuration
public class MyBootstrapConfiguration {
#Bean
#ConditionalOnMissingBean
public ApiClient apiClient() {
return someClient;
}
}
Now in my test (junit-5 and #SpringBootTest), I would like to override this bean. Notice the #ConditionalOnMissingBean... If I can hook somehow to a "before" my bootstrap is started, to provide that ApiClient, that method apiClient would obviously not be called and I would be happy.
Please notice that MyBootstrapConfiguration is not something I have control of - its an invariant to me. For non-bootstrap configuration this is easily doable, but is there a way to do this for bootstrap?
Given a test configuration class:
#Configuration
public class TestBootstrapConfiguration implements Ordered {
#Bean
public ApiClient testApiClient() {
return testApiClient;
}
#Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
In src/test/resources/META-INF/spring.factories
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
TestBootstrapConfiguration

Spring inject a bean into another bean

I am trying to inject a bean into another bean that uses it. How can I do this?
public class MySpringConfig{
#Bean
public MyObject getMyObject() {
//.....
return MyObjectInstance;
}
#Bean
public SomeObject getSomeObject(MyObject myObject) {
//.....
return SomeObjectInstance;
}
}
I think you can do this with this way, this is working in my project.
#Configuration
public class AppConfig {
#Bean
public Bean1 foo(#Qualifier("bean2") Bean2 bean2) {
return new Bean1(bean2);
}
}
i think that might work!
#Configuration
public class AppConfig {
#Bean
public Bean2 bean2() {
return new Bean2();
}
#Bean
#DependsOn({"bean2"})
public Bean1 foo(#Autowired Bean2 bean2) {
return new Bean1(bean2); // or your can write new Bean1(bean2());
}
}
Parameters don't work exactly in the same way in #Bean and #Component.
For a class annotated with #Component, specifying them is required for the autowired constructor but in a #Bean declaration you don't need to provide a parameter to specify the MyObject dependency to use (while it will work) if that is accessible in the current class, which is your case.
So you want to inject directly the bean by invoking getMyObject() in the #Bean definition.
For example to pass it a constructor arg :
#Bean
public SomeObject getSomeObject() {
//....
// you injected MyObject in the current bean to create
SomeObject object = new SomeObject(getMyObject());
//...
return SomeObjectInstance;
}
And don't forget to annotate the class with #Configuration to make it considered by Spring.

How to use multiple spring configuration files

I have a java spring configuration defined like so,
#Configuration
public class FirstConfiguration {
#Bean
FirstController firstController() {
return new FirstController(firstService());
}
#Bean
FirstService firstService() {
return new FirstServiceImpl(secondService());
}
}
Now the beans in this configuration depend on SecondConfiguration defined like so,
#Configuration
public class SecondConfiguration {
#Bean
SecondController SecondController() {
return new SecondController(SecondService());
}
#Bean
SecondService secondService() {
return new SecondServiceImpl();
}
}
How can I make use of the secondService() bean in my FirstConfiguration?
Since the SecondService is a bean, you could inject it into the firstService method to configure another bean:
#Bean
FirstService firstService(#Autowired SecondService secondService) {
return new FirstServiceImpl(secondService);
}
You can inject the firstService like this :
#Autowired
SecondService secondService
You can refer the method secondService() directly when you import the configuration.
#Configuration
#Import(SecondConfiguration.class)
public class FirstConfiguration {
#Bean
FirstController firstController() {
return new FirstController(firstService());
}
#Bean
SomeController someController() {
return new SomeController(secondService());
}
}
Refer the Spring config import

How do I express a dependency on a bean defined in an imported configuration in Spring?

I recently started working at a place that uses Java configuration for Spring as opposed to XML and so far I'm loving it.
My question is the following:
If we have a #Configuration annotated class A that imports another #Configuration annotated class B, what is the proper, type-safe way for a bean defined in A to depend on a bean defined in B.
Here's an example I saw in a blog (https://blog.codecentric.de/en/2012/07/spring-dependency-injection-styles-why-i-love-java-based-configuration/):
#Configuration
public class PartnerConfig {
#Bean
public PartnerService partnerService() {
return new PartnerServiceImpl();
}
}
#Configuration
#Import(PartnerConfig.class)
public class CashingConfig {
#Autowired
private PartnerConfig partnerConfig;
#Bean
public CashingService cashingService() {
return new CashingServiceImpl(partnerConfig.partnerService());
}
}
As a second part to my question, if I was to do the above, would Spring interpret as a bean dependency? That is, when I do
partnerConfig.partnerService()
in the example above, am I getting Spring to fetch me the partnerService bean, or am I just calling a regular java method and creating a new instance of the PartherService (which is NOT what I want, since the bean should be a singleton) ?
EDIT:
It has been suggested to use a #Qualifier. Would this work?
#Configuration
public class PartnerConfig {
#Bean
#MyCustomQualifier
public PartnerService partnerService() {
return new PartnerServiceImpl();
}
}
#Configuration
#Import(PartnerConfig.class)
public class CashingConfig {
#Bean
public CashingService cashingService(#MyCustomQualifier PartnerService partnerService) {
return new CashingServiceImpl(partnerService);
}
}
I recommend giving the docs a read: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Bean.html
Refer to the section:
#Bean Methods in #Configuration Classes
This sums it up very well.
Typically, #Bean methods are declared within #Configuration classes. In this case, bean methods may reference other #Bean methods in the same class by calling them directly. This ensures that references between beans are strongly typed and navigable.
Also take a look at: http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html
Section:
Composing #Configuration classes
Just add the dependency as an argument to the #Bean annotated method and remove the autowiring of the configuration.
#Configuration
#Import(PartnerConfig.class)
public class CashingConfig {
#Bean
public CashingService cashingService(PartnerService partnerService) {
return new CashingServiceImpl(partnerService);
}
}
or simply autowire the PartnerService instead of the configuration.
#Configuration
#Import(PartnerConfig.class)
public class CashingConfig {
#Autowire
private PartnerService partnerService;
#Bean
public CashingService cashingService() {
return new CashingServiceImpl(partnerService);
}
}

Categories