Specify specific bean to be injected from specific configuration class - java

I am having one problem where bean definition for a single Service are defined in 2 different configuration classes.
#Configuration
public class ConfigurationA{
#Primary
#Bean("beana")
public beanA(){
return Mockito.mock(BeanA.class);
}
#Bean("beanb")
public beanB(){
return new BeanB(beanA());
}
#PostConstruct
public void initialize(){
beanA().dosomething();
}
}
#Configuration
public class ConfigurationB{
#Bean("beana")
public beanA(){
return new BeanA();
}
}
So when intialize() method is called, I am expecting mocked instance of BeanA will be used but its using real instance that is injected via ConfigurationB class.
I have marked "beana" as primary bean so spring should Ideally use this instance but its using the actual real instance defined in different configuration class.
Is there any way we can configure to use the bean definition from ConfigurationA class instead of ConfigurationB?

Related

Different behavior in calling #Bean annotated methods

I am aware of calling #Bean annotated methods from within a #Configuration as already discussed.
But I don't understand why it doesn't work when the bean is overwritten.
I have a legacy class, which I can't modify. It's a configuration and a business bean at the same time. This is a simplified version:
#Configuration
public class MyBean {
String someMethod() {
return otherBean() + "|" + otherBean();
}
int called = 0;
#Bean
Object otherBean() {
return called ++;
}
}
Inside the someMethod() the factory method otherBean() is called two times and as far as annotated with #Bean the instance should be gotten from the Spring context and therefore should the actual code return called ++; be called only once. Expected output from the someMethod() should be always 0|0 and it is so indeed in the production.
Trouble comes when I am about to redefine the bean in a unit test:
#SpringJUnitConfig//(MyBean.class)
public class BeanTest {
#Autowired
MyBean myBean;
#Test
void testIt() {
assertEquals("0|0", myBean.someMethod());
}
#Configuration
static class TestConfig {    
#Bean
MyBean myBean() {
return new MyBean();
}
}
}
The reason could be some additional settings of the MyBean instance in the test (not included in the snippet above).
Now, calling myBean.someMethod() returns 0|1 instead of 0|0.
Everything works again (result is 0|0), when the TestConfig configuration is removed and configuration of the test context is set as #SpringJUnitConfig(MyBean.class).
What's different in registering the bean in the test?
The "magic" of proxying method calls annotated with #Bean and returning instances from the Spring context happens only in configuration beans (like here: #SpringJUnitConfig(MyBean.class)).
But when you create a new instance as return new MyBean(), the #Configuration annotation is ignored and the object is registered as a normal bean (#Bean MyBean myBean()) but not a configuration. That's why the methods calls otherBean() create always a new instance.

How to qualify bean with constructor injection

I have an interface which is defined in two places like that:
#Configuration
public class AppContext {
#Bean
public SomeInterface usageOne() {
return new SameImpl();
}
#Bean
public SomeInterface usageTwo() {
return new SameImpl(someOtherConfig);
}
#Bean
public Client clientOne(SomeInterface usageOne) {
return new Client(usageOne);
}
#Bean
public OtherClient clientTwo(SomeInterface usageTwo) {
return new OtherClient(usageTwo);
}
}
My client implementation classes do not have any annotations only required constructor. How to qualify the correct interface implementation usage in that case? I don't want to use #Primary as in my case it's semantically incorrect to name one of the usages as primary (they are in some sense equal). I need to pass the same interface with the same implementation class but configured differently for specific use cases of respected clients. I was thinking that naming the parameter by which I inject the implementation to the bean creation method is enough, but Spring complains with: required a single bean, but 2 were found. I don't understand how should I use the #Qualifier annotation.
I'm running with Spring Boot 2.0.4.RELEASE and respected beans and clients created in separate configuration classes so I cannot just call usageTwo() method when creating OtherClient like that: new OtherClient(usageTwo()); as this method is not available in clients configuration class.
As mentioned by #chrylis in the comments, you can simply add the #Qualifier annotation to the #Bean methods like this:
#Bean
public Client clientOne(#Qualifier("usageOne") SomeInterface usageOne) {
return new Client(usageOne);
}
#Bean
public OtherClient clientTwo(#Qualifier("usageTwo") SomeInterface usageTwo) {
return new OtherClient(usageTwo);
}
The value specified as value for the #Qualifier annotation is the respective bean's name. That is either the name of the corresponding #Bean method or the value of the annotation if used like this #Bean("usageThree").

Behaviour of lite #Bean methods in Spring 5

From the Spring 5 docs
When #Bean methods are declared within classes that are not annotated
with #Configuration they are referred to as being processed in a
'lite' mode. Bean methods declared in a #Component or even in a plain
old class will be considered 'lite', with a different primary purpose
of the containing class and an #Bean method just being a sort of bonus
there. For example, service components may expose management views to
the container through an additional #Bean method on each applicable
component class. In such scenarios, #Bean methods are a simple
general-purpose factory method mechanism.
Unlike full #Configuration, lite #Bean methods cannot declare
inter-bean dependencies. Instead, they operate on their containing
component’s internal state and optionally on arguments that they may
declare. Such an #Bean method should therefore not invoke other #Bean
methods; each such method is literally just a factory method for a
particular bean reference, without any special runtime semantics. The
positive side-effect here is that no CGLIB subclassing has to be
applied at runtime, so there are no limitations in terms of class
design (i.e. the containing class may nevertheless be final etc).
The #Bean methods in a regular Spring component are processed
differently than their counterparts inside a Spring #Configuration
class. The difference is that #Component classes are not enhanced with
CGLIB to intercept the invocation of methods and fields. CGLIB
proxying is the means by which invoking methods or fields within #Bean
methods in #Configuration classes creates bean metadata references to
collaborating objects; such methods are not invoked with normal Java
semantics but rather go through the container in order to provide the
usual lifecycle management and proxying of Spring beans even when
referring to other beans via programmatic calls to #Bean methods. In
contrast, invoking a method or field in an #Bean method within a plain
#Component class has standard Java semantics, with no special CGLIB
processing or other constraints applying.
I would have expected that the following code throws an exception / bean1.bean2 to be null and that the init method would not be executed. However, the code below runs fine and prints:
Should never be invoked
Expected null but is ch.litebeans.Bean2#402bba4f
So for me it looks like lite beans behave the same as beans constructed from an #Configuration annotated class. Can someone point out in which scenario this is not the case?
.
package ch.litebeans;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ApplicationConfig.class);
Bean1 bean1 = ctx.getBean(Bean1.class);
System.out.println("Expected null but is " + bean1.getBean2());
}
}
package ch.litebeans;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
#Configuration
#ComponentScan(basePackages = {"ch.litebeans"})
public class ApplicationConfig {}
package ch.litebeans;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
#Component
public class Factory1 {
#Bean
public Bean1 getBean1(Bean2 bean2){
return new Bean1(bean2);
}
}
package ch.litebeans;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
#Component
public class Factory2 {
#Bean(initMethod = "init")
public Bean2 getBean2(){
return new Bean2();
}
}
package ch.litebeans;
public class Bean1 {
private Bean2 bean2;
public Bean1(Bean2 bean2){
this.bean2 = bean2;
}
public Bean2 getBean2(){
return bean2;
}
}
package ch.litebeans;
public class Bean2 {
public void init(){
System.out.println("Should never be invoked");
}
}
EDIT:
Based on the explanation of Mike Hill I added an example demonstrating the difference:
public class BeanLiteRunner {
public static void main(String[] args) {
AnnotationConfigApplicationContext acac = new AnnotationConfigApplicationContext(MyComponent.class,
MyConfiguration.class);
MyComponent.MyComponentBean1 componentBean1 = acac.getBean(MyComponent.MyComponentBean1.class);
MyComponent.MyComponentBean1 componentBean2 = acac.getBean(MyComponent.MyComponentBean1.class);
MyConfiguration.MyConfigurationBean1 configurationBean1 = acac.getBean(MyConfiguration
.MyConfigurationBean1.class);
MyConfiguration.MyConfigurationBean1 configurationBean2 = acac.getBean(MyConfiguration
.MyConfigurationBean1.class);
}
}
#Component
public class MyComponent {
#Bean
public MyComponent.MyComponentBean1 getMyComponentBean1(){
return new MyComponent.MyComponentBean1(getMyComponentBean2());
}
#Bean
public MyComponent.MyComponentBean2 getMyComponentBean2(){
return new MyComponent.MyComponentBean2();
}
public static class MyComponentBean1{
public MyComponentBean1(MyComponent.MyComponentBean2 myComponentBean2){
}
}
public static class MyComponentBean2{
public MyComponentBean2(){
System.out.println("Creating MyComponentBean2");
}
}
}
#Configuration
public class MyConfiguration {
#Bean
public MyConfigurationBean1 getMyConfigurationBean1(){
return new MyConfigurationBean1(getMyConfigrationBean2());
}
#Bean
public MyConfigurationBean2 getMyConfigrationBean2(){
return new MyConfigurationBean2();
}
public static class MyConfigurationBean1{
public MyConfigurationBean1(MyConfigurationBean2 myConfigurationBean2){}
}
public static class MyConfigurationBean2{
public MyConfigurationBean2(){
System.out.println("Creating MyConfigrationBean2");
}
}
}
The output is as expected
> Creating MyComponentBean2
> Creating MyComponentBean2
> Creating MyConfigrationBean2
This is not a bug. Spring's lite bean definitions are automatically added to the context during the component scan. Bean definitions using a factory method (i.e., all #Bean-defined beans) will automatically attempt to autowire parameters using the current context. See ConstructorResolver#instantiateUsingFactoryMethod for more details.
The referenced documentation is perhaps not entirely clear. The primary differentiation between "lite" and "full" bean configurations is strictly the proxying that is done in "full" (#Configuration) mode. Take for example what would happen if we instead defined our beans in a #Configuration class:
#Configuration
public MyConfiguration {
#Bean
public Bean1 bean1() {
return new Bean1(bean2());
}
#Bean
public Bean2 bean2() {
return new Bean2();
}
}
The call to bean2() from within bean1() will actually reference the singleton bean2 instance from the context rather than directly calling the bean2() method as implemented. In fact, it doesn't matter how many bean2() method calls are made from within that configuration class -- the real bean2 method will only be executed one time.
"Lite"-mode does not proxy these methods, meaning that each bean2() method call will actually directly reference the method implementation and will not return the bean that is in the context. Rather, it will create a new separate instance that is not tracked by the context (as is the default Java behavior).

Using AOP scoped proxy to autowire prototype bean in a singleton bean

I was able to test that autowiring a prototype bean, within a singleton bean results in only a single prototype bean being created.
As a solution to that, I read that I could define AOP scoped proxy for the prototype bean or use Spring's lookup method injection.
Here is what I have tried -
PrototypeBean.java
#Component
#Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.INTERFACES)
public class PrototypeBean implements Prototype {
private String welcomeMessage;
public String getWelcomeMessage() {
return welcomeMessage;
}
public void setWelcomeMessage(final String welcomeMessage) {
this.welcomeMessage = welcomeMessage;
}
}
SingletonBean.java
#Component
public class SingletonBean implements Singleton{
#Autowired private Prototype prototype;
public Prototype getPrototype() {
return prototype;
}
public void greet() {
System.out.println(prototype.getWelcomeMessage());
}
}
Test Class
public class AutowiredDependenciesDemo {
#Autowired private Singleton autowiredSingleton;
#Autowired ConfigurableApplicationContext context;
#Test
public void testPrototypeBeanWithAopScopedProxy(){
Assert.assertNotNull(autowiredSingleton);
Prototype prototypeBean = (Prototype) ((SingletonBean) autowiredSingleton).getPrototype();
prototypeBean.setWelcomeMessage("hello world");
autowiredSingleton.greet();
Singleton contextSingleton = (Singleton) context.getBean("singletonBean");
Assert.assertSame(autowiredSingleton, contextSingleton);
Prototype anotherPrototypeBean = (Prototype) ((SingletonBean)contextSingleton).getPrototype();
anotherPrototypeBean.setWelcomeMessage("hello india");
contextSingleton.greet();
autowiredSingleton.greet();
// i expected both the prototype instances to be different. in the debugger, it does show two different 'proxied' instances. however the test fails.
Assert.assertNotSame(prototypeBean, anotherPrototypeBean);
}
Am I missing something here ? Also, the calls to greet() method return null.
There are things you mix in your thinking about Proxies and prototype beans.
When Spring Framework injects a Prototype Scoped bean into a Singleton Scoped bean then it creates a Proxy object (which implements all required interfaces) and injects it instead of instance of the Prototype bean. Then, whenever method is called on this Prototype Proxy, Spring creates a new instance and the method is called on this new instance.
In your case - in test - you only compare injected Proxies and they are the same because there exists only 1 proxy for the Prototype Bean and this Proxy is responsible for creation of new instance of the Prototype Bean whenever needed.
Here is my example:
I have an interface Prototype and its implementation PrototypeImpl. In my test I obtain bean of type Prototype directly from ApplicationContext and I also inject it using #Autowired. Then in debugger I see this:
Notice that there is only one and the same Proxy (look at its address) but calling 'toString()' on this proxy shows two different addresses of the PrototypeImpl objects. Which shows exactly what I have written above.
EDIT: Info about un-proxying
To extend the comment by M. Deinum you can extract the underlying object from the Proxy in the following way:
Prototype extracted = null;
if(AopUtils.isAopProxy(a) && a instanceof Advised) {
Object target = ((Advised)a).getTargetSource().getTarget();
extracted = (Prototype) target;
}

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