Can I scope a CDI bean to be a singleton? Why am I seeing my @ApplicationScoped bean constructed twice?
sboscarine Feb 5, 2013 3:10 PMHello All,
Can I make a CDI bean be a singleton? I am having an issue w/ CDI and must be misunderstanding something very fundamental.
Here's what I'd like to do:
- Scope a bean so there's only 1 copy shared among all the applications to store application configuration data.
- Make it mutable to allow different classes to update it on rare occasion so we can:
- read the latest value without a reboot
- and not hit the source of the configuration value (a database) every time it's read.
You could say I want to use a CDI bean as a cache.
Here's what I did:
- Wrote a simple @ApplicationScoped bean to store my value
- Wrote 3 consumers that inject it using @Inject.
- Created an event listener that updates the value when I call a REST service.
- Added instrumentation to print when it is being constructed.
I noticed the following:
- 2 copies of the @ApplicationScoped bean were constructed (I had 3 consumers and was hoping only 1 would be constructed).
- When I update the value in one instances, my other instance doesn't see the modifications.
The main consumer
@WebListener
public class WebSessionTimeoutFilter implements HttpSessionListener {
private static final Logger logger = LoggerFactory.getLogger(WebSessionTimeoutFilter.class);
@Override
public void sessionCreated(HttpSessionEvent event) {
final int timoutInMin = settings.getGUITimeoutInMinutes();
final int guiTimeoutInSeconds = timoutInMin * 60;
event.getSession().setMaxInactiveInterval(guiTimeoutInSeconds);// in seconds
logger.info("Session created. Timeout is " + timoutInMin + " min");
}
@Override
public void sessionDestroyed(HttpSessionEvent event) { }
@Inject @WebappConfig
private WebappSettings settings;
}
Here's my bean:
@ApplicationScoped
public class WebappSettings {
public WebappSettings(){
System.out.println("\n" + this.getClass().getSimpleName() + " was constructed\n"); //This is called twice on startup.
}
@Min(1) @Max(180) //standard JSR303 BeanValidation
private int GUITimeoutInMinutes;
public int getGUITimeoutInMinutes() {
return GUITimeoutInMinutes;
}
public String toString() {
return "WebappSettings [GUITimeoutInMinutes=" + GUITimeoutInMinutes + "]";
}
}
Here's the code to produce it and update it (same class):
//My update method.
public void refreshValues(@SuppressWarnings("unused") @Observes ConfigurationUpdateEvent event) {
logger.info("\n old value=" + currentSettings);
MyUpdateLogic.updateMe(currentSettings, config.getFinalConfig()); //my update logic...works correctly, I can see the value updated as expected.
logger.info("\n updated value=" + currentSettings);
}
@Inject @WebappConfig
private WebappSettings currentSettings;
//...
//My producer method.
@Produces
@WebappConfig
public WebappSettings produceWebappSettings() {
WebappSettings settings = new WebappSettings();
MyUpdateLogic.updateMe(settings, config.getFinalConfig());
return settings;
}
Why aren't all the consumers using the same instance as each other?
WebappSettings is @ApplicationsScoped. Why do I see it constructed twice on startup?
How can I make a bean a Singleton in CDI?