Spring's BeanFactory getBean method returns JDK proxy when using #Async (with custom thread executor) - spring

I am new to spring and trying to understand the framework. I have a class (say ClassA) which has execute() method. I am using "prototype" scope (#Scope) for this class.I am using #Async("customThreadPoolTaskExecutor) for this execute() method. I have already defined this customThreadPoolTaskExecutor in another class with #Configuration. Then I have another class (say ClassB) which uses BeanFactory of spring to get an object of ClassA using beanFactory.getBean(ClassA).
I am getting an error on this line inside ClassB
ClassA A = (ClassA) beanFactory.getBean(ClassA);
Error is as below
org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'ClassA' is expected to be of type 'ClassA' but was actually of type 'jdk.proxy2.$Proxy103'
Note that above code works fine and returns an object of ClassA if I remove #Async from execute() method of ClassA.
I am looking to understand the root of the problem and clear some of my concepts about spring. What is the relationship between #Async and bean creation using BeanFactory's getBean method. Why does it work without #Async but not with #Async.
Note : The fix/workaround I have so far is to add "ScopedProxyMode" for ClassA as "TARGET_CLASS". After adding this to ClassA's #Scope annotation, things work ok but I am not able to understand the root cause of the issue.

Related

#MockBean injected into a constructor-autowired component

From the official documentation:
When registered by type, any existing single bean of a matching type (including subclasses) in the context will be replaced by the mock
What if the service under test is autowired in the constructor, though? E.g. in Kotlin (I suppose #MockkBean and #MockBean work the same regarding DI):
#RunWith(SpringRunner.class)
class ExampleTests #Autowired constructor(val userOfService: UserOfService) {
#MockkBean
private lateinit var service: ExampleService
...
}
I would expect this example to fail because in order to instantiate ExampleTests Spring has to first obtain a proper instance of UserOfService. That shouldn't be possible at that time, though, because there's no bean of type ExampleService in the application context yet.
Contrary to my expectation, this works. How is it possible?
Because you miss the other part from the documentation :
In either case, if no existing bean is defined a new one will be
added.
So #MockBean will also instantiate a bean automatically if that bean is not found in the spring context.
The sequence of actions are mainly as follows :
Start up the spring context which create all the spring BeanDefinition only that are registered in the spring context.
Process #MockBean which will replace the BeanDefinition in (1) or create a new BeanDefinition
Actually instantiate all the beans based on these BeanDefinition. It will handle which bean to be actually instantiated first and later.
Create a test instance (i.e ExampleTests) to execute its test methods. If any beans required to be auto-wired into the test instance are not created , it will fail.
So as long as you define UserOfService bean , ExampleTests can be instantiated as you are now using #MockBean on the ExampleService which means it must exist no matter you define it or not in the spring context for the test.

Is dependency injected if scope is prototype in Spring if we don't use getBean method

I wanted to know if we only do ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml"); in our main method and don't do Coach coach1=context.getBean("myCoach5",Coach.class); where suppose "Coach" is my class and "myCoach5" is id of bean having prototype scope defined in applicationContext.xml. Then in case of prototype-scope will constructor led dependency be injected? Will its constructor's content run?
I observe it does not work in prototype scope but works in case of singleton scope with everything else remaining the same.

#PostConstrution called multiple times

I have created a class which implements two interfaces.
I have used a init method with #postconstruction annotation
I am observing that though bean is initialised only during start up, init method is called multiple times.
The #PostConstruct method will be called every time the bean is instantiated. This means either every time you do a "new", or, if you've registered your class with a #Service, #Repository, or any other anotation of sorts that registers the class as a spring bean, the first time you #Autowired it.
Watch out for instantations of the class aside from those if you are using another framework annotations like #ManagedBean in JSF, which could be instantiating your class without you realising it.

Spring lookup-method and scoped proxy usage

I'm a bit confused about using method injection (lookup-method) and aop scoped-proxy (Since both used for different scoped beans injection) so
1) When to use method injection and when to use aop-scoped proxy ?
2) What is the reason why a aop-scoped proxy will not be used for a prototype bean ?
Both lookup method injection and scoped proxy are means to inject shorter lived beans into longer lived beans. However, they serve different use cases.
Method injection is useful in cases where a singleton-scoped bean has a dependency on a prototype-scoped bean.
A proxy gets injected in place of the desired bean and provides that bean depending on the context. For example, if a singleton bean (such as a Spring MVC controller) auto-wires a session scoped bean, then the proxy delivers that bean belonging to the current HTTP session.
Such a proxy doesn't apply well to a situation where a prototype bean shall be obtained at runtime. Lookup method injection is one way to obtain prototype instances at runtime.
However, method injection has limitations because it builds upon abstract methods. Hence, certain things like writing unit tests are more cumbersome, as you need to provide a stub implementation of the abstract method. Component scanning doesn't work with abstract classes either.
One alternative to method injection is Spring's ObjectFactory, or its JSR equivalent Provider.
Another, straightforward way of creating prototype bean instances at runtime (which even makes it possible to provide constructor arguments) is to implement a bean factory like the following:
#Configuration
public class MyProvider {
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public MyThing create(String name) {
return new MyThing(name);
}
}
Usage:
#Component
public class MySingleton {
#Autowired
private MyProvider myProvider;
public void doStuffThatNeedsAPrototypeBeanInstance() {
MyThing thing = myProvider.create("some name");
...
}
}
For the question 1. When to use method injection and when to use aop-scoped proxy?
Let's say you have a singleton bean A has dependency on the prototype bean B. A has a method m which has B involved.
You got the object a of A and execute the method m several times. Every time m executing, a new object b of B needs to inject to a. That's the time you use the method injection.
Besides, if you have a singleton bean A has dependency on the session bean B. A has a method m which has B involved.
You got the object a of A and execute the method m several times. As long as the execution time is in a same session, a has the same object b of B. That's the time you use proxy.

Is it possible to retrieve a Spring bean with prototype scope without using ApplicationContextAware

Using Spring 3.1. If I want to retrieve a bean with prototype scope (i.e. I want a different instance of the class each time), is it possible to retrieve the bean without having to use an ApplicationContextaware class?
This is how I do it at present
#Component
#Qualifier("MyService")
public class MyServiceImpl implements MyService {
#Override
public void doSomething() {
Blah blah = (Blah)ApplicationContextProvider.getContext().getBean("blah");
blah.setThing("thing");
blah.doSomething();
}
}
#Component("blah")
#Scope("prototype")
public class Blah {
....
}
where ApplicationContextProvider implements ApplicationContextAware.
Is it possible to do this with annotations or simple Spring configuration without having to use an ApplicationContextAware class?
Spring has some fairly sophosticated methods for achieving what you're after...
See the spring documentation: http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/beans.html#beans-factory-scopes-other-injection
Searching for spring proxy scope on google also threw up some results...
You don't really need a ApplicationContextAware. You just need a BeanFactory (ApplicationContextAware is just a convinient way to get it).
A bean with scope prototype just means that everytime ApplicationContext.getBean is called a new instance of the bean is created. If you try to inject a prototype bean in a singleton, your prototype bean will be injected once (and so is no more a prototype).
There is something called method injection that may help you if you really need it, but it is more complex than simply calling applicationContext.getBean().

Resources