Spring autowiring order and #PostConstruct - java

I have a question about auto-wiring order and #PostConstruct logic in Spring. For example following demo code I have a main Spring Boot class:
#SpringBootApplication
public class Demo1Application {
#Autowired
BeanB beanb;
public static void main(String[] args) {
SpringApplication.run(Demo1Application.class, args);
}
}
and 2 #Service Definitions:
#Service
public class BeanB {
#Autowired
private BeanA beana ;
#PostConstruct
public void init(){
System.out.println("beanb is called");
}
public void printMe(){
System.out.println("print me is called in Bean B");
}
}
#Service
public class BeanA {
#Autowired
private BeanB b;
#PostConstruct
public void init(){
System.out.println("bean a is called");
b.printMe();
}
}
and I have the following output:
bean a is called
print me is called in Bean B
beanb is called
My question is how autowiring takes place step by step like a scenario above?
And how printMe() method of beanb is called without calling its #PostConstruct first?

Below should be possible sequence
beanb starts to get autowired
During class initialization of Beanb, beana starts to get autowired
Once beana gets created the #PostConstruct i.e. init() of beana gets called
Inside init(), System.out.println("bean a is called"); gets called
Then b.printMe(); gets called causing System.out.println("print me is called in Bean B"); to execute
Having the beana completed the #PostConstruct i.e. init() of beanb gets called
Then System.out.println("beanb is called"); gets called
Ideally the same can be better observed by a debugger in eclipse.
The Spring reference manual explains how circular dependencies are resolved. The beans are instantiated first, then injected into each other.

Your Answer is Correct as you shown in Your question.
Now Getting the concept of Notation #Autowired. All #Autowired Objects are initialized and loaded in memory just after class Loading is done.
Now here is your SpringBootApplication
#SpringBootApplication
public class Demo1Application {
#Autowired
BeanB beanb; // You are trying to autowire a Bean class Named BeanB.
Here at above Console Application that you have write try to autowire and inject a object of type BeanB.
Now here is your definition of BeanB
#Service
public class BeanB {
#Autowired
private BeanA beana ;
In BeanB class you are trying to inject the Object of Class BeanA which is also defined in your console Project.
So, In Your Demo1Application to inject a Object of Class BeanB there must need to inject a Object of class BeanA.
Now BeanA Class Object is Created First.
Now if you see the definition of Your Class BeanA
#Service
public class BeanA {
#Autowired
private BeanB b;
#PostConstruct // after Creating bean init() will be execute.
public void init(){
System.out.println("bean a is called");
b.printMe();
}
}
So, After injecting the Object BeanA method bind with #PostContruct annotation is going to execute.
So, execution flow will be..
System.out.println("bean a is called");
System.out.println("print me is called in Bean B");
System.out.println("beanb is called");

It will show class not found exception as class A depends on class B. and class B depends on class A.

Related

Injecting spring beans in non managed objects

the below bean of Class I want to inject in other non-managed bean, but it is not working as expected
#Component
#Setter
#Getter
public class AbstractLayoutProperties {
#Value("${spring.application.name}")
private String appName;
#Autowired
S3Service s3Service;
#Autowired
S3Client s3Client;
}
Below is the class which is not managed by the spring, but I am using #Configurable
#Configurable(preConstruction = true, autowire = Autowire.BY_NAME)
#EnableSpringConfigured
public class OverlayServiceImpl
implements GenericVehicleOverlayService<T, R> {
public findOnlyActive(){
appName = layoutProperties.getAppName(); // throwint NullPointerException beacuse the object not injected properly
}
#Autowired
AbstractLayoutProperties layoutProperties;
}
One more point, findOnlyActive method I am not calling directly, I am calling this from another service, lets say
#Service
public class OtherService{
public void findActive(){
OverlayServiceImpl impl=new OverlayServiceImpl();
impl.findOnlyActive();
}
#Autowired
OtherRepository otherRepo;
}
Problem statrement:
when impl.findOnlyActive(); is executed, it should inject all the required beans inside OverlayServiceImpl. In the same class I have two beans which are autowired, it seems none of them injected, this is the reaosn that every time I am encountering Nullpointer exception. so my question is how do I make it work, what are the steps and action I need to take so that spring will inject the dependencies in non managed object i,e OverlayServiceImpl.

Spring Autowiring with Inheritance

I'm relatively new to Spring, and I'm trying to understand an issue I'm experiencing in which a dependency is not being autowired into a bean that is the parent of another bean that is being constructed.
The parent class is specified as follows. Note that I've abbreviated some of the logic for clarity. The Log class is implemented as an entity.
#Component
#Scope("prototype")
public class AppTransaction {
private String componentName;
#Autowired
private LogRepository logRepository;
public AppTransaction(String componentName) {
this.componentName = componentName;
}
public void writeLog(String logText) {
Log log = new Log(this.componentName, logText);
this.logRepository.save(log);
}
}
The child class is implemented as follows.
#Component
#Scope("prototype")
public class EmployeeJobTransaction extends AppTransaction {
#Autowired
private EmployeeRepository employeeRepository;
private String componentName;
private String jobName;
public EmployeeJobTransaction(String componentName, String jobName) {
super(componentName);
this.jobName = jobName;
}
public List<String> doJob() {
List<String> statuses = this.employeeRepository.getEmployeeJobStatuses();
writeLog("Job complete.");
}
}
In my service class, I'm using the application context to get an instance of the EmployeeJobTransaction bean. I'm doing this because the input parameters to the EmployeeJobTransaction bean are based on user input.
#Service
public class JobServiceImpl {
#Autowired
private ApplicationContext applicationContext;
public void initJob() {
EmployeeJobTransaction employeeJobTransaction = this.applicationContext.getBean(EmployeeJobTransaction.class, "EmployeeComponent", "CheckEmployeeJobStatus");
jobTransaction.doJob();
}
}
When I get the EmployeeJobTransaction bean, the EmployeeRepository bean is autowired as expected. However, the AppTransaction instance created does not appear to be a Spring-managed bean because the LogRepository object that has been autowired is null. I'm assuming this is because the call to super() in the EmployeeJobTransaction class does not create an instance of AppTransaction as a Spring-managed bean.
What are my options? Must I autowire the LogRepository bean into the EmployeeJobTransaction class and then pass it to the writeLog method as a parameter? I'm not understanding why the parent class is not created as a Spring bean when the child class is created as such.
For those that may come across this question in the future, I understand now that I was interpreting what Spring was doing incorrectly.
I turned on debugging and had set a breakpoint in the AppTransaction constructor.
public AppTransaction(String componentName) {
this.componentName = componentName; //Breakpoint here
}
When I executed my logic, I was confused because the autowired LogRepository bean was null.
According to the Spring documentation:
Fields are injected right after construction of a bean, before any config methods are invoked.
Therefore, it makes sense that the LogRepository bean is null in the constructor. When the writeLog method is called, the LogRepository bean is not null because it was successfully autowired AFTER the construction of the AppTransaction bean.
Thanks to those who responded.
TLDR: Autowired fields are null inside the constructor of a bean. The beans are not autowired until the construction of the bean in which they are referenced has completed.
I think you are a littel confused. I will try to explain me:
Your code shows 3 Spring beans:
AppTransaction
With an autowired dependency of the logRepository
EmployeeJobTransaction
With an autowired dependency of the employeeRepository
With an autowired dependency of the logRepository (inhereted of the parent class AppTransaction)
JobServiceImpl
When you call to he super method on EmployeeJobTransaction you are not calling to AppTransaction bean. You are calling to the parent class constructor method.
Is unnecessary to have a Spring bean of the AppTransaction class (remove the Component and Scope annotations of this class)
When you call to getBean method, Spring create a new bean each time. I think this is unnecessary. You could declare EmployeeJobTransaction bean as singleton (remove de Scope annotation) and to add the componentName and jobName attributes as parameters of doJob method.
I think woult be the best way.

Is there a way to call a method in a bean after all spring context is initialized

I have a problem and this is the gist of it: (there are more classes involved in the loop but it can be represented this way)
#service
public class serviceDispatcher{
#Autowired
private BeanA a;
#Autowired
private BeanB b;
public BeanA getBeanA(){
return a;
}
public BeanB getBeanB(){
return b;
}
}
#Service
public class BeanA{
#Autowired
ServiceDispatcher sd;
#PostConstruct
private void init(){
sd.getBeanB().method;
}
}
so obviously I get a null pointer since BeanB b is not yet resolved. I also used afterPropertiesSet and it is the same. My question is that if there is a way to run the init() method after the whole context is initialized so that I don't get this null pointer? I am aware of the fact that having this circular dependency is trouble and needs to be solved but I'm just refactoring a huge project to use Spring DI and changing the design, logic and business requires a long process of asking it to be done by other teams.
You will have to subscribe to ContextRefreshedEvent event in order to execute your code once spring context is full initialized.
#Component
class N51348516 implements ApplicationListener<ContextRefreshedEvent> {
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println(event.getApplicationContext());
}
}
But I guess what you really need is to make your bean lazy with #Lazy annotation so you will be able to access them correctly.
I don't understand why you need to use the serviceDispatcher in the first place. You could try to directly inject BeanB into BeanA:
#Service
public class BeanA{
private BeanB beanB;
#Autowired
public BeanA(BeanB b){
beanB = b;
beanB.someMethod();
}
}
For the class BeanA, add the annotation #DependsOn("beanB")

Execution Order of #PostConstruct

I have 2 singletons in my JEE application that I want to initialize at start up. Something like this:
#Singleton
#Startup
public class ServiceB {
#EJB
private ServiceA a;
#PostConstruct
private void init() {
....
}
}
ServiceB doesn't really need ServiceA, I just added the dependency to make sure that ServiceA is fully initialized (read: #PostConstruct-method finished) before ServiceB's init() -Method starts.
But it doesn't wait. ServiceB actually starts before ServiceA.
Is there any way to ensure that one Bean's #PostConstruct- method waits for another Bean's #PostConstruct-method to finish?
I know I could just remove the #PostConstruct Annotation in ServiceA and call it directly from ServiceB
#PostConstruct init() {
a.init();
}
but I have deployments where there is no ServiceB. So I can't rely on ServiceB to init ServiceA. ServiceA has to do that itself. And ServiceB must wait for ServiceA to be done with it.
Use the #DependsOn annotation to declare an initialization dependency on startup beans.
Example:
#Singleton
#Startup
public class ServiceA {
#PostConstruct
public void init() { ... }
}
#Singleton
#Startup
#DependsOn("ServiceA")
public class ServiceB {
#EJB
ServiceA a;
#PostConstruct
public void init() { ... } // will be called after a is initialized
}
A question on the answer given by #DmiN
(I am new user so not able to post a comment directly)
With your suggestion (as shown in code below) -- I agree that Service B will start after Service A is initialized (just initialized, not that postconstruct is complete). But I doubt if it can be guaranteed that ServiceB's init method will never run unless the Service A's PostConstruct method has finished execution? Correct?
#Singleton
#Startup
public class ServiceA {
#PostConstruct
public void init() { ... }
}
#Singleton
#Startup
#DependsOn("ServiceA")
public class ServiceB {
#EJB
ServiceA a;
#PostConstruct
public void init() { ... } // will be called after a is initialized
}
The #PostConstruct annotation is used for methods executed after dependency injection is complete, So here the injection of service A in service B is done, then the init function of Service B can be executed
public class ServiceA {
#PostConstruct
public void init() { }
}
public class ServiceB {
#Autowired
ServiceA a;
#PostConstruct
public void init() { }
}
As a simple alternative solution, you can manually collect all your independent beans that should be inited in a defined order in one place. It helps to avoid #DependsOn
public interface OrderedPostConstruct {
void init();
}
// ==== Production ====
#Configuration
public class InitConfig {
private final ObjectProvider<OrderedPostConstruct> initializers;
#PostConstruct
public void initEntryPoint() {
initializers.orderedStream().forEach(Initialize::init);
}
}
#Order(1)
#Component
public class OneUsefullComponent implements OrderedPostConstruct {
#Override
public void init() {
// executed first
}
}
#Order(2)
#Component
public class TwoUsefullComponent implements OrderedPostConstruct {
#Override
public void init() {
// executed second
}
}
// ==== Integration tests ====
#Order(Ordered.HIGHEST_PRECEDENCE)
#Component
public class TestDataPopulator implements OrderedPostConstruct {
#Override
public void init() {
// populate data for tests
}
}

why this bean is not null

The following code works fine in spring 4, but I am wondering why the getBean(FooService.class) returns an already-loaded bean. I thought the sequence of bean loading is not guaranteed, meaning that it is possible to get a null bean. Is it because the loading target is a class not a String (ie. object) or is it because the FooService bean has a special scope, like prototype? If so, what is the difference between getBean(class) and getBean(object)
public abstract class AbstractService implements ApplicationContextAware {
protected ApplicationContext applicationContext;
protected FooService fooService;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
#PostConstruct
protected void postConstruct() {
fooService = applicationContext.getBean(FooServiceImpl.class);
}
ApplicationContext::getBean method creates the bean of the specified type if it has not been created already.
For the following two bean classes:
#Component
public class Bean1 {
#Autowired
private ApplicationContext applicationContext;
public Bean1() {
System.out.println("Bean 1 constructor");
}
#PostConstruct
public void init() {
System.out.println("Bean 1 #PostConstruct started");
applicationContext.getBean(Bean2.class);
System.out.println("Bean 1 #PostConstruct completed");
}
}
#Component
public class Bean2 {
#Autowired
private ApplicationContext applicationContext;
public Bean2() {
System.out.println("Bean 2 constructor");
}
#PostConstruct
public void init() {
System.out.println("Bean 2 #PostConstruct started");
applicationContext.getBean(Bean1.class);
System.out.println("Bean 2 #PostConstruct completed");
}
}
the printed output during context initialization is:
Bean 1 constructor
Bean 1 #PostConstruct started
Bean 2 constructor
Bean 2 #PostConstruct started
Bean 2 #PostConstruct completed
Bean 1 #PostConstruct completed
As for different getBean methods, if you pass in a class, then exactly one bean of that class has to be present in the application context (otherwise Spring would not not which of multiple bean instances of that class you ask for), whereas searching by name allows you to get a specific named bean instance.
For starters, String is a full rights class, like any you can create yourself.
The reason you're getting something in fooService, is that the ApplicationContext getBean method is able to retrieve a managed bean according to the argument you're passing to it.
If it weren't possible to retrieve the bean, you could get some of these exceptions:
Throws: NoSuchBeanDefinitionException - if no bean of the given type
was found NoUniqueBeanDefinitionException - if more than one bean of
the given type was found BeansException - if the bean could not be
created

Categories