5 Replies Latest reply: Feb 7, 2012 7:00 AM by Daniel Straub RSS

    Multiple @Singleton Instances

    Bernd Eckenfels Novice

      If I deploy my Test MessageDrivenBean on 7.0.1 standalone-preview profile with a @EJB dependency to a @Singleton, I can see, that the Singleton class (constructor) is called on each instanciation of a MDB, therefore I have more than one java class, not a real singleton.

       

      However the postContruct() Method is only called for the first Singleton.

       

      13:15:37,864 INFO  [stdout] (Thread-6049 (group:HornetQ-client-global-threads-3178554)) EJB3Singleton() Startup...13084479
      13:15:37,864 INFO  [stdout] (Thread-6049 (group:HornetQ-client-global-threads-3178554)) EJB3MDB.initialize()
      13:15:37,864 INFO  [stdout] (Thread-6049 (group:HornetQ-client-global-threads-3178554)) onMessage() START
      13:15:37,895 INFO  [stdout] (Thread-6049 (group:HornetQ-client-global-threads-3178554)) EJB3Singleton() Startup...23965508
      13:15:37,895 INFO  [stdout] (Thread-6049 (group:HornetQ-client-global-threads-3178554)) EJB3Singleton() Post Construct...23965508
      13:15:37,958 INFO  [stdout] (Thread-6049 (group:HornetQ-client-global-threads-3178554)) EJB3Singleton() returning hash....23965508
      13:15:37,958 INFO  [stdout] (Thread-6049 (group:HornetQ-client-global-threads-3178554)) my singleton: 23965508
      13:15:39,958 INFO  [stdout] (Thread-6049 (group:HornetQ-client-global-threads-3178554)) onMessage() DONE
      
      13:16:05,381 INFO  [stdout] (Thread-6031 (group:HornetQ-client-global-threads-3178554)) onMessage() START
      13:16:05,396 INFO  [stdout] (Thread-6031 (group:HornetQ-client-global-threads-3178554)) EJB3Singleton() returning hash....23965508
      13:16:05,396 INFO  [stdout] (Thread-6031 (group:HornetQ-client-global-threads-3178554)) my singleton: 23965508
      13:16:07,396 INFO  [stdout] (Thread-6031 (group:HornetQ-client-global-threads-3178554)) onMessage() DONE
      
      13:16:11,162 INFO  [stdout] (Thread-6050 (group:HornetQ-client-global-threads-3178554)) onMessage() START
      13:16:11,162 INFO  [stdout] (Thread-6050 (group:HornetQ-client-global-threads-3178554)) EJB3Singleton() returning hash....23965508
      13:16:11,162 INFO  [stdout] (Thread-6050 (group:HornetQ-client-global-threads-3178554)) my singleton: 23965508
      13:16:11,303 INFO  [stdout] (Thread-6051 (group:HornetQ-client-global-threads-3178554)) EJB3Singleton() Startup...26566365
      13:16:11,303 INFO  [stdout] (Thread-6051 (group:HornetQ-client-global-threads-3178554)) EJB3MDB.initialize()
      13:16:11,303 INFO  [stdout] (Thread-6051 (group:HornetQ-client-global-threads-3178554)) onMessage() START
      13:16:11,303 INFO  [stdout] (Thread-6051 (group:HornetQ-client-global-threads-3178554)) EJB3Singleton() returning hash....23965508
      13:16:11,303 INFO  [stdout] (Thread-6051 (group:HornetQ-client-global-threads-3178554)) my singleton: 23965508
      13:16:13,162 INFO  [stdout] (Thread-6050 (group:HornetQ-client-global-threads-3178554)) onMessage() DONE
      13:16:13,303 INFO  [stdout] (Thread-6051 (group:HornetQ-client-global-threads-3178554)) onMessage() DONE
      

       

       

      As you can see in 13:15:37,864; 13:15:37,895 and 13:16:11,303 a new Java Class (constructor) was created, but only the second instance have been "postConstructed" and injected. Is this a problem with the dependency injector? The EJB 3.1 spec is not clear if the container is actualy allowed to instanciate and default-construct more than one singleton instance.

       

      Singleton looks like:

       

      @Singleton
      @LocalBean
      @ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
      //@Startup
      @Lock(LockType.READ)
      public class EJB3Singleton
      {
          public EJB3Singleton() {
              System.out.println("EJB3Singleton() Startup..." + this.hashCode());
          }
      
          @PostConstruct
          public void postConstruct() {
              System.out.println("EJB3Singleton() Post Construct..." + this.hashCode());
          }
      
          @PreDestroy
          public void preDestroy() {
              System.out.println("EJB3Singleton() Pre Destroy..." + this.hashCode());
          }
      
          public int getHash() {
              System.out.println("EJB3Singleton() returning hash...." + this.hashCode());
              return this.hashCode();
          }
      }
      

       

       

      Markup fix: Bernd Eckenfels

        • 1. Re: Multiple @Singleton Instances
          Carlo de Wolf Master

          The EJB3Singleton class also serves as the class for the no-interface view of the EJB3Singleton EJB.

           

          So the Singleton EJB is initialized once, while you'll see multiple proxies being instantiated for servicing the no-interface view.

          • 2. Re: Multiple @Singleton Instances
            Bernd Eckenfels Novice

            Ok, why does it have to be multiple proxies? Would it help to use a business Interface here? Is this covered by the EJB spec?

            • 3. Re: Multiple @Singleton Instances
              jaikiran pai Master

              From the spec:

              The developer of an enterprise bean that exposes a no-interface view must not make any assumptions about the number of times the bean class  no-arg constructor will be called. For example, it is possible that the acquisition of a client reference to the no-interface view will result in the invocation of the bean-class constructor.

              • 4. Re: Multiple @Singleton Instances
                Bernd Eckenfels Novice

                Thanks, I just made the test with a Business Interface for the Singleton Class, and indeed, the default constructor is only called once, anymore.

                • 5. Re: Multiple @Singleton Instances
                  Daniel Straub Newbie

                  We run in the same problem (with 7.1.0CR1b) :

                  Using a @Singleton (with Business Interface) as a @Producer for a Cache, the Cache is injected in other @Singleton/@Startup EJB's in different jars.

                  Every time the cache is injected, a new instance of the @Singleton is created.

                   

                   

                  @Singleton

                  @Startup

                  @Local(CacheProvider.class)

                  public class CacheProviderImpl implements CacheProvider {

                   

                      private static final Log LOG = LogFactory.getLog(CacheProviderImpl.class);

                   

                      private Cache<?, ?> cache;

                   

                      public CacheProviderImpl() {

                          LOG.info("CacheProvider created " + this);

                          startCache();

                      }

                   

                      @Produces

                      public Cache getCache() {

                          return cache;

                      }

                   

                      //@PostConstruct -> https://issues.jboss.org/browse/AS7-2785

                      public void startCache() {

                      ...

                   

                   

                  [CacheProviderImpl] CacheProvider created CacheProviderImpl@c5cd1a

                  ...

                  [CacheProviderImpl] CacheProvider created CacheProviderImpl@150f2ec

                  ...

                  [CacheProviderImpl] CacheProvider created CacheProviderImpl@eff6e7

                   

                   

                  What is wrong in this scenario ?