3 Replies Latest reply on Feb 13, 2013 3:46 PM by Rich DiCroce

    EJB and CDI internals

    Rich DiCroce Novice

      I just read this article by David Blevins, a member of the EJB 3.0/3.1/3.2 Expert Groups. One of the first things he says is that "EJBs are CDI beans" which surprised me, because I had been under the impression that EJB and CDI were separate (though related) frameworks.

       

      So now, I'm curious. How do EJB and CDI operate in AS7? Are they completely separate or do they share some plumbing? I'm especially curious because one of my co-workers insists that we can't use (or rather, shouldn't use) EJBs in one of our projects because they're "heavyweight"... and so instead we're using CDI beans everywhere (and duplicating the same transaction logic a zillion times, much to my annoyance).

       

      So if EJB and CDI use the same plumbing internally, I'd love to just switch all these things to EJBs. If not, does anyone have any data regarding the performance of EJBs vs CDI beans? I could make an experiment to find out, but it probably wouldn't be very scientific, and would be a waste of time if someone else has already benchmarked it.

        • 1. Re: EJB and CDI internals
          Nicklas Karlsson Master

          The component models are a bit blurred now (since JSF has their own managed beans and hopefully JAX-RS doesn't add  to the mix in the next EE rev) but hopefully they move towards a more unified model with the managed bean specification.

           

          EJBs can exist without CDI (obviously) and CDI can exist without EJBs (POJOs). When they are used together (e.g @SessionScoped @Stateful) you get a small CDI proxy that wraps the EJB and provides e.g. decorators, lifecycle management and the other stuff.

          I would go for EJB + CDI in most cases. A local-interface-only EJB is not that heavy and the transaction benefits it brings are nice. Of course you don't have to use EJB for everything, POJOs are fine for helper classes that don't persist etc. As for performance, if you run e.g.

          a JSF web app, the time spent constructing the view is minimal compared to the extra CDI-EJB proxies.

           

          First it used to be "Java is soooo slow". Then it was "EJB is sooooo heavyweight".

          • 2. Re: EJB and CDI internals
            Stephen Coy Master

            Your co-worker is not "keeping up" at all.

             

            One of the best places to catch up in a single location is Adam Bien's blog.

            • 3. Re: EJB and CDI internals
              Rich DiCroce Novice

              Nicklas, Stephen: thanks for your replies. I just conducted a not especially scientific test to guage the performance difference. Code included for anyone who wants to duplicate my test. If you just want to know the outcome, skip to the last line of this post.

               

              First, I made an EJB:

               

              {code}

              import javax.ejb.ConcurrencyManagement;

              import javax.ejb.ConcurrencyManagementType;

              import javax.ejb.Singleton;

               

               

              @Singleton

              @ConcurrencyManagement(ConcurrencyManagementType.BEAN)

              public class EJBPerfTester {

               

               

                        public void doStuff() {

                                  long total = 0;

                                  for (int i = 0; i < 1000000; i++) {

                                            total += i;

                                  }

                                  System.out.println("total is " + total);

                        }

               

              }

              {code}

               

              Then I made a roughly equivalent CDI bean:

               

              {code}

              @ApplicationScoped

              public class CDIPerfTester {

               

               

                        @Inject

                        private UserTransaction tx;

               

                        public void doStuff() {

                                  try {

                                            tx.begin();

                                            long total = 0;

                                            for (int i = 0; i < 1000000; i++) {

                                                      total += i;

                                            }

                                            tx.commit();

                                            System.out.println("total is " + total);

                                  } catch (Exception e) {

                                            throw new RuntimeException(e);

                                  }

                        }

               

              }

              {code}

               

              Note that the EJB has bean-managed concurrency, attempting to match the fact that CDI doesn't manage concurrency. The EJB does have default transaction semantics, so the CDI bean explicitly starts and commits a transaction to match. The EJB is a singleton while the CDI bean is application scoped, so they are roughly the same in that area as well. Both do the exact same "work" of adding up a bunch of numbers and printing the result.

               

              Then I have a JSF bean, into which the two beans are @Inject'ed, with some XHTML to invoke them. That's not especially important as these beans could be invoked in any number of ways, and the timing code explicitly attempts to minimize the influence of anything else:

               

              {code}

              Stopwatch sw = new Stopwatch();

               

              sw.start();

              ejbTester.doStuff();

              sw.stop();

              long ejbTime = sw.elapsedTime(TimeUnit.MICROSECONDS);

               

               

              sw.reset();

               

               

              sw.start();

              cdiTester.doStuff();

              sw.stop();

              long cdiTime = sw.elapsedTime(TimeUnit.MICROSECONDS);

               

               

              L.infov("EJB Time: {0} us, CDI Time: {1} us, Difference: {2} us", ejbTime, cdiTime, ejbTime - cdiTime);

              {code}

               

              The stopwatch is from Google Guava, the logger is JBoss Logging, not that the latter makes much difference as you could just use a System.out.println() there.

               

              You might notice I'm measuring the time in microseconds. That is because the difference in performance is not discernable at the millisecond level. On my machine, if there is really a penalty for the EJB, it is at most 140 microseconds. I say "if there is really a difference" because there appear to be some other factors influencing the timings, despite my best efforts. For example, if I switch the order of the invocations, and run the CDI bean first, the difference hovers around 20 microseconds instead of 140, despite the fact that everything else is exactly the same.

               

              Regardless, a tenth of a millisecond (again, assuming that's not caused by something else) is an incredibly tiny amount of overhead. So for anyone else out there who's wondering about EJB vs CDI performance: it appears there is effectively no difference on AS7.