3 Replies Latest reply on Feb 7, 2013 3:11 AM by mkouba

    Can I scope a CDI bean to be a singleton?  Why am I seeing my @ApplicationScoped bean constructed twice?

    sboscarine

      Hello 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?