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

    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.

       

      {code}

      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

      {code}

       

      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:

       

      {code}

      @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();

          }

      }

      {code}

       

      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.

          1 of 1 people found this helpful
          • 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 ?