Reputation: 397
I have CDI based application. At runtime my application generates custom event that causes bean reload. Bean reload means go through all beans and reinitialize already injected beans. Reinitialization should be aware of beans dependencies. For example:
class BeanA {
String url;
@PostConstruct
void init(){
url = UrlFactory.getNewUrl()
}
}
class BeanB {
@Inject
BeanA beanA;
@PostConstruct
void init(){
url = beanA.getUrl();
doSomethingWith(url);
}
Hence, when event comes, BeanA and BeanB should be reinitialized in strict order, so during BeanB reinitialization BeanB already aware of new url initialized in BeanA. Is it possible to do at runtime using already existing tools within CDI (something like in Spring: AutowireCapableBeanFactory)? I found that EJB already has @DependsOn annotation that is capable of building bean order during application start up.
The most brute force solution I came up with is listen to one of CDI events during application start up, collect all beans and build dependency graph and during reload go through this graph and do reinitialization. I'm afraid I'm not aware of many pitfalls that I might run into (like cyclic dependencies, lazy initialization (it might not work at all in this case) and many others I'm not aware of, because does not have pretty good understanding of how CDI container works internally)
Are there any other existing techniques that actually solve my problem?
Upvotes: 1
Views: 390
Reputation: 16238
First, make a producer method that @Produces
your String
-typed url
value (maybe create a @URL
qualifier annotation to further identify it). Produce this in @Dependent
scope. Something like:
@Produces @Dependent @URL private static final String produceUrl() {
return UrlFactory.getNewUrl();
}
Now anywhere someone does @Inject @URL private String url
they'll get a new String
representation of a URL from your UrlFactory
.
More importantly, anytime anyone does @Inject @URL private Provider<String> urlProvider;
they'll get a Provider
whose get()
method, when invoked, will return the latest and greatest URL value.
This may be all you need if you look at it right.
If it's not all you need, then make BeanA
do this:
@Inject
@URL
private Provider<String> urlProvider;
…and then in its (omitted above) getUrl()
method, do this:
public String getUrl() {
return this.urlProvider.get();
}
You'll get a new String
each time.
If you've done that, then you can just add BeanA
to your observer method and have it handed to you:
private static final void onEvent(@Observes final YourEvent event, final BeanA beanA) {
final String url = beanA.getUrl(); // latest and greatest
}
Upvotes: 1