Reputation: 15225
I'm using Spring 3.1.3 for a webapp, using XML configuration with component scanning.
I realized that one of the scanned components has to be initialized before several others. On all the classes that need post-construct initialization, I have a @PostConstruct
annotation on a method.
To set up the dependency order, I changed @Component
to @Component("configData")
on the class that needs to be post-constructed before the others. I then added @DependsOn("configData")
just before each class definition that needs to be post-constructed AFTER the configData bean.
From what I've read, this is all I need to enforce the dependency order.
I then built everything, set my breakpoints, and started up the app. I expected to hit the breakpoint in the configData bean before any of the dependent beans. This isn't what happened. The first breakpoint was in the init
method of one of the dependent beans.
I then changed my log4j.xml
file to set debug as the logging level for org.springframework
and reran my test. The breakpoint behavior was the same, and my logging didn't show any debug information about Spring initialization (I have debugging on for log4j initialization itself, so I confirmed that I had DEBUG set for org.springframework
).
What might I be missing?
Update:
If it matters, here are a couple of skeleton examples of what I'm doing here.
@Component("configData")
public class ConfigData {
....
@PostConstruct
public void init() {
....
}
}
@Component
@DependsOn("configData")
public class ClassDependentOnConfigData extends BaseClass {
....
@Override
@PostConstruct
public void init() {
super.init();
....
}
}
To reiterate, what I'm finding at runtime is that the init()
method in ClassDependentOnConfigData
is being called by Spring before the init()
method in ConfigData
.
Note also that BaseClass
has an @Autowired
for ConfigData
.
Upvotes: 27
Views: 41253
Reputation: 526
Working in a multi-module project faced the same issue where @DependsOn
annotation wont do anything.
Problem
You have a bean that depends on another bean, and the @DependsOn
annotation is not effectively managing the initialization order as expected.
Workaround Solution
Use the @Lazy
annotation on the dependent bean. This forces Spring to defer the initialization of this bean until it is actually needed, ensuring that all other beans are initialized first.
@Lazy
Annotation: By annotating DependentBean with @Lazy, you are instructing Spring to create and initialize this bean only when it is first needed, rather than during the application startup phase. This allows DependencyBean to be fully initialized before DependentBean is created.
Note: This solution is not the most elegant and may bring other challenges, I suggest to use this as workaround only.
Upvotes: 0
Reputation: 15225
(From someone else's correct but now deleted answer)
The @DependsOn
contract only guarantees that the bean has been constructed and properties have been set. This will not guarantee that any @PostConstruct
methods have been called.
The way to get this to work is to have the dependee class (the class that others depend on) implement the InitializingBean
interface, which requires implementing the afterPropertiesSet()
method. I put the original body of my init()
method into this method. I verified that this is now executed before any of the classes that depend on this.
Another thing that was mentioned in the original answer is that if I had defined my dependee bean in XML and used the init-method
property, this WOULD have executed before any of the classes that depend on this. I didn't verify this.
Upvotes: 26
Reputation: 116
I also encoutered the same problem, but still not properly resolved. As a part of a solution Spring documentation says:
"Using DependsOn at the class level has no effect unless component-scanning is being used."
This is the reason why the @dependsOn annotation has no effect.
Upvotes: 9