I'm new to Spring, I would like to know:
I have a java class annotated with #Component (spring) and inside I have a method annotated with #PostConstruct. The class is then referenced by #Autowired annotated field in another class. Can I assume that the class is only injected after #PostConstruct is called?
#Component
class AuthenticationMetrics {
private static final MetricRegistry metrics = new MetricRegistry();
final Counter requestsTotal;
final Meter guestLogins;
final Meter kfUserLogins;
final Timer guestLoginResponseTime;
final Timer kfLoginResponseTime;
#PostConstruct
public void populateMetricsRegistry() {
metrics.counter("authentication.requests.totals");
}
}
If you are asking is injection of given class happening after #PostConstruct in that bean is called, then the answer is yes - #PostConstruct is executed before bean is considered as "injectable"
If you are asking if #PostConstruct on given bean is executed after all injections has been done (on the same bean) - then yes - #PostConstruct is executed after injections are commited to given bean. This is the reason it exists. Normally you could put #PostConstruct actions into the constructor. However, when new object is created (constructor is called) injections are not performed yet - so any initialization that depends on injected objects would fail due to NPE. That is why you need #PostConstruct
The handling of annotations such as #PostConstruct, #Resource, #PreDestroy is done via a BeanPostProcessor, in this case the CommonAnnotationBeanPostProcessor. You can see in the following diagram from Spring that these BPP's are handled after Dependency Injection but before Bean Ready For Use (Which means as much as injectable).
Yes. Bean creation workflow is:
constructior call
#Autowired fields
#Autowired setters
BeanPostProcessor's postProcessBeforeInitialization(), i.e. #PostConstruct called by CommonAnnotationBeanPostProcessor
InitializingBean.afterPropertiesSet()
BeanPostProcessor's postProcessAfterInitialization()
Bean is ready and can be injected to other bean
Related
I'm using a configuration class that uses dynamic bean registration:
#Configuration
public class ConfigClass {
#Autowired
private GenericApplicationContext applicationContext;
#PostConstruct
private void init() {
System.out.println("init");
applicationContext.registerBean("exService", ExecutorService.class, () -> Executors.newFixedThreadPool(10), bd -> bd.setAutowireCandidate(true));
System.out.println("init done");
}
}
If I try to autowire the bean, application startup fails with error Field exService in com.example.DemoApplication required a bean of type 'java.util.concurrent.ExecutorService' that could not be found.
From the logs I can see that the init method on config class wasn't called before the error as the two system out statements were not printed out.
However, when I use applicationContext.getBean(ExecutorService.class) it does work without any issues.
Anyway I can get the bean to Autowire?
I'm deliberately not using the #Bean annotation because I need to register the beans dynamically based on certain conditions.
It could be because you are registering your bean in the middle of the context initialization phase. If your target bean initializes and auto-wires ExecutorService before ConfigClass #PostConstruct is invoked there simply is no bean available.
You can try forcing the initialization order:
#Component
#DependsOn("configClass")
public class MyComponent
#Autowired
private ExecutorService executorService;
However it would be cleaner to register a bean definition using BeanFactoryPostProcessor with BeanDefinitionBuilder:
#Component
public class MyBeanRegistration implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory bf) {
BeanDefinitionRegistry reg = (BeanDefinitionRegistry) bf;
reg.registerBeanDefinition("exService",
BeanDefinitionBuilder
.rootBeanDefinition(ExecutorService.class)
.setFactoryMethod("newWorkStealingPool")
.getBeanDefinition());
}
}
You can do like this:
#Resource
#Lazy
private ExecutorService executorService;
It works.
Actually, I wrote the small infrastructure that deals with such issues. Here is the idea how to do this:
Create a class (lets call it MyClass) that incapsulates ExecutorService.class as a property and declare it as Bean (#Component). Even before that create an Interface (Lets call it MyInterface) that your new class would implement
Create a factory class (Lets call it MyFactory) with method MyInterface getInstance(String) that returnce an instance of your interface. In that factory crate a static property Map[String, MyInterface] and public static method that allows you to add instances of the interface to this map
In MyClass create a constructor that at the end will place newly created instance of itself into that map in the factory with the key of your class name ("MyClass")
Now The trick is that when Spring starts and initializes it creates all its beans. As your MyClass will be created its constructor will place its instance into a factory. So now anywhere in your code you can call:
MyInterface myInterface = MyFactory.getInstance("MyClass");
And you get your bean without worrying about instantiating it. Spring already did it for you. Big extra bonus is non-intrucivness - you don't have to explicitely work with Spring classes
I'm working with some existing code and it is doing things I haven't seen before. I've dealt with autowiring prototype beans into singletons using method injection or getting the bean from the context using getBean(). What I am seeing in this code I am working on is a bean that is a prototype and retrieved using getBean(), and it has autowired dependencies. Most of these are singleton beans, which makes sense. But there is an autowire of another prototype bean, and from what I see, it does seem like it is getting a new bean. My question is when you autowire a prototype into a prototype, will that give you a new instance? Since the autowire request is not at startup but rather when this bean is created, does it go and create a new instance? This goes against what I thought about autowire and prototype beans and I wanted to hear an answer from out in the wild. Thanks for any insight. I'm trying to minimize my refactoring of this code as it is a bit spaghetti-ish.
example:
#Scope("prototype")
public class MyPrototypeClass {
#Autowired
private ReallyGoodSingletonService svc;
#Autowired
private APrototypeBean bean;
public void doSomething() {
bean.doAThing();
}
}
#Scope("prototype)
public class APrototypeBean {
private int stuffgoeshere;
public void doAThing() {
}
}
So when doSomething() in MyPrototypeClass is called, is that "bean" a singleton or a new one for each instance of MyPrototypeClass?
In your example, the APrototypeBean bean will be set to a brand new bean which will live through until the instance of MyPrototypeClass that you created is destroyed.
If you create a second instance of MyPrototypeClass then that second instance will receive its own APrototypeBean. With your current configuration, every time you call doSomething(), the method will be invoked on an instance of APrototypeBean that is unique for that MyPrototypeClass object.
Your understanding of #Autowired or autowiring in general is flawed. Autowiring occurs when an instance of the bean is created and not at startup.
If you would have a singleton bean that is lazy and that bean isn't directly used nothing would happen as soon as you would retrieve the bean using for instance getBean on the application context an instance would be created, dependencies get wired, BeanPostProcessors get applied etc.
This is the same for each and every type of bean it will be processed as soon as it is created not before that.
Now to answer your question a prototype bean is a prototype bean so yes you will receive fresh instances with each call to getBean.
Adding more explanation to #Mark Laren's answer.
As explained in Spring 4.1.6 docs
In most application scenarios, most beans in the container are
singletons. When a singleton bean needs to collaborate with another
singleton bean, or a non-singleton bean needs to collaborate with
another non-singleton bean, you typically handle the dependency by
defining one bean as a property of the other. A problem arises when
the bean lifecycles are different. Suppose singleton bean A needs to
use non-singleton (prototype) bean B, perhaps on each method
invocation on A. The container only creates the singleton bean A once,
and thus only gets one opportunity to set the properties. The
container cannot provide bean A with a new instance of bean B every
time one is needed.
Below approach will solve this problem, but this is not desirable because this code couples business code with Spring framework and violating IOC pattern. The following is an example of this approach:
// a class that uses a stateful Command-style class to perform some processing
package fiona.apple;
// Spring-API imports
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class CommandManager implements ApplicationContextAware {
private ApplicationContext applicationContext;
public Object process(Map commandState) {
// grab a new instance of the appropriate Command
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
protected Command createCommand() {
// notice the Spring API dependency!
return this.applicationContext.getBean("command", Command.class);
}
public void setApplicationContext(
ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
So, there are 2 desirable ways to solve this problem.
1. Using Spring's method injection
As name suggests, Spring will implement & inject our abstract method by using #Lookup annotation from Spring 4 or tag if you use xml version. Refer this DZone article.
By using #Lookup.
from Java Doc...
An annotation that indicates 'lookup' methods, to be overridden by the
container to redirect them back to the BeanFactory for a getBean call.
This is essentially an annotation-based version of the XML
lookup-method attribute, resulting in the same runtime arrangement.
Since:
4.1
#Component
public class MyClass1 {
doSomething() {
myClass2();
}
//I want this method to return MyClass2 prototype
#Lookup
public MyClass2 myClass2(){
return null; // No need to declare this method as "abstract" method as
//we were doing with earlier versions of Spring & <lookup-method> xml version.
//Spring will treat this method as abstract method and spring itself will provide implementation for this method dynamically.
}
}
The above example will create new myClass2 instance each time.
2. Using Provider from Java EE (Dependency Injection for Java (JSR 330)).
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
#Component
public static class SomeRequest {}
#Service
public static class SomeService {
#Autowired
javax.inject.Provider<SomeRequest> someRequestProvider;
SomeRequest doSomething() {
return someRequestProvider.get();
}
}
The above example will create new SomeRequest instance each time.
I have a BaseDaoImpl class, it has following method:
#Autowired
public void initSessionFactory(#Qualifier("sqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
super.setSqlSessionFactory(sqlSessionFactory);
System.out.println("------ ok ------");
}
I defined a subclass UserDaoImpl, which implements BaseDaoImpl. And defined it as a bean.
When init Spring context, I found that the initSessionFactory() method is executed automatically, but I didn't call any methods.
In my understanding, the method is executed & autowire its params only when I call it, can someone help to explain how it works? Thanks.
That behavior is normal. Your initSessionFactory method annotated with #Autowired is considered to be a config method. #Autowired can be placed on constructors, fields and methods. When the bean is created, first the constructor is called, then the fields are injected and then config methods are called.
A config method's (annotated with #Autowired) arguments will be autowired with a matching bean in the Spring container.
See the Javadoc API for Autowired annotation for more details.
I have this requirement: I have a singleton bean and I have a method annotated with #PostConstruct where I perform some initialization. One of the initialization is to read some values from a DB, so I want to inject in this method a Stateless bean which is a service bean that access the DB. I don't want to inject the stateless bean as a field in the singleton bean because it is needed only in this method (nowhere else in the singleton bean). To do so I did wrote this in singleton bean:
#Singleton
public class MySingletonBean {
#PostConstruct
#EJB
public void init(SLSBService service) { /* use service to read from DB */ };
...
}
The problem is that the Singleton bean can not be instantiated. Any idea? Thank you in advance.
As the #PostConstruct annotated (callback) method is actually called after all references are resolved (all beans injected) I do not think this construct works.
What you could do or try out is to remove the #PostConstruct and using normal setter injection. However, be aware that other injected resources have not necessarily been resolved at this time.
#EJB
public void setService(SLSBService service){
service.doSmg();
}
#Stateless
public class SLSBService{
#PersistenceContext
private EntityManager em;
#TransactionAttribute(TransactionAttributeType.MANDATORY)
public void doSmg() {
Member member = new Member();
member.setEmail("bla#bla.de");
member.setName("fubu");
member.setPhoneNumber("453454534535");
em.persist(member);
}
}
/* edit */
Just had some time for trying it out. The construct should be usable for DAOs, as the method is executed within a transaction and also the EntityManager (within the SLBService) is injected properly. And as expected references to other EJBs have not be resolved yet, so be aware of that.
I have a resource (Spring bean) which has some of its fields injected by Spring, for example:
#Repository(value="appDao")
public class AppDaoImpl implements AppDao {
#PersistenceContext
EntityManager entityManager;
public Resource() {
... use entityManager ... // doesn't work
}
}
I know that I can't access the injected entityManager in the constructor and should use a #PostConstruct annotation on a different method. But what are the reasons for this?
Because Spring can't access any fields or methods before the object is created (which is done through the constructor). So Spring instantiates the object using the constructor and then injects the properties.
The only way around this is to use Constructor Injection (which can be cumbersome if you have multiple dependencies). I think what you should do is move your code out of the constructor and into an initialization method using the #PostConstruct annotation:
#PostConstruct
public void init(){
// do stuff with entitymanager here
}
The reason is in the lifecycle of the bean:
The container (spring application context) instantiates the object
then it sets all the dependencies (incl. the entityManager in your example)
after all dependencies have been set, it invokes the #PostConstruct method, if any.
Spring (and no one) can set fields to an object before actually constructing that object.
You can use constructor-injection - passing the dependencies to a non-default constructor, but it is not possible with #PersistenceContext