10

We are starting a new project based on EJB 3.0. I have a "spring" based background (and love it), so for me loose coupling and testability is a big must have. This post should not be about "ejb vs. spring". It would be perfect if you already have real project experience with this.

here is some example code to demonstrate the problem:

client -> ejb -> collaborator 1 -> collaborator .. -> collaborator n

<!-- language: java -->
@Stateless
public class SampleService {

    // or @Inject via CDI
    // or @Autowired via Spring
    @EJB // or just use a stateless session bean via EJB 3.0
    private Bank bank;

    // same for this component
    @EJB
    private Calculator calc;

    // both collaborators must be settable from outside, to make everything testable (and mockable)

    /**
     * sample "business service" called from client
     */
    public void debit(BigDecimal amount){
        calc.calculate(amount.subtract(new BigDecimal(100)));
        bank.debit(amount);
    }

}

// or via @Component (Spring), or CDI?
@Stateless // or Stateless Session bean with optional @Service/@Singleton annotation?
public class Calculator {
    public void calculate(BigDecimal subtract) {
        // calculate stuff....
    }
}

// or via @Component (Spring), or CDI?
@Stateless // or Stateless Session bean with optional @Service/@Singleton annotation?
public class Bank {
    public void debit(BigDecimal amount) {
        // ...
    }
}

i want to know what is the best way to implement dependency injection for all the collaborators and their collaborators in ejb 3.0? collaborators in this sense can be very very small dedicated classes.

we have discussed the the following options so far and like always don't have a proper conclusion yet :)

  1. only use the ejb standard with everything beeing a stateless session bean and all consequences (like pooling, resource handling etc.)

  2. use stateless session beans as "business components" (entry points) and from there on

a) spring wired dependencies (via "jboss snowdrop" integration)

b) CDI wired dependencies (via WELD for ejb 3.0 and jboss eap 5.1)

i don't need to know how i can use the beans in a unit test. the answer i am after is what is the best approach to wire up all the dependencies inside the running appserver (spring vs. guice vs. CDI vs. EJB). i only need to know the graph from the outer EJB ("business entry point") downwards. so everything outside (servlets, frontend etc.) is not scope of this question :)

please, assume EJB 3.0 and jboss eap 5.1 are set for the project :)

looking forward to your answers and hopefully some project based knowledge.

Arjan Tijms
  • 37,782
  • 12
  • 108
  • 140
Marcel
  • 710
  • 8
  • 23

4 Answers4

4

If you need method level transaction management, security, concurrency management or any other services that a session bean can offer then make them EJB session beans. You can start out with managed beans and then make them session beans as and when you need to.

If you want to inject these session beans into managed beans (which in CDI is anything in a jar file that contains a beans.xml file in the meta-inf directory) then use @EJB. If you want to inject a plain managed bean into a session bean use @Inject.

If you want to inject remote session beans (or any Java EE remote resource) then this link explains how you can do this via an adapter class. Essentially it keeps all of your nasty strings for lookups etc in one place and allows you then to treat these remote resources just like any other injectable bean (via the @Produces annotation on the adapter member variables). You don't have to do this but it is recommended.

Typesafe resource injection

Arjan Tijms
  • 37,782
  • 12
  • 108
  • 140
user695654
  • 103
  • 5
3

I would definitely vote against mixing frameworks.

I'm working on a project that is hooked on EJB, Spring and JBoss Seam (and also has half-Flex, half-JSF front-end). A true technology zoo!
Anyway, wiring it all together is not the worst part, those frameworks have flexible injection capabilities. Testing is also more or less bearable.
The most painful was to get rid of memory leaks caused by different lifecylce models, synchronize transaction, and clean up threading behavior.

Now we're moving to pure Java EE 6 (getting rid of Spring, Flex and shifting from Seam to CDI). So far we're really pleased with the results. BTW, I'm not criticizing Spring. Stick with either Java EE or Spring stack, mixing them is just asking for trouble.

Yuri
  • 1,695
  • 1
  • 13
  • 23
2

Well in general in Java there are "too many choices," so certainly in this area as well. I would not describe EJB as a general purpose Dependency Injection framework, rather they use DI for their purposes. If that is how you want to code, you should look to add a framework for this purpose. If you know and like Spring, go for it. I have used Guice with EJB's (here is a nice cookbook) to good effect as well, if you needed yet another framework to figure out how to do this.

Yishai
  • 90,445
  • 31
  • 189
  • 263
0

If your main goal is to allow dependency injection for testing I would recommend just letting those values be settable via changing them to protected or giving them setters. I'm a fan of using Mockito to stub everything in Java EE EJB 3.0 and when doing any testing outside of integration testing to just allow Mockito to stub the methods for me, but if you are looking for full dependency injection like the capability to have several different beans based off of the same class, but with different dependencies I would recommend as Yishai said and going with Spring on top.

Arjan Tijms
  • 37,782
  • 12
  • 108
  • 140
Shane
  • 467
  • 1
  • 4
  • 12
  • thanks for your answer. yes, it's mainly for testing. i am curious if people say "yes, every bean (collaborator) can be a stateless session bean" or if people say "don't mix these frameworks" and so on. i also heard people saying "just let everything be a stateless session bean. the container is made for pooling, handling of resources etc.. don't just use a DI framework like spring or guice - that would be premature optimization" .... so too many choices leave people confused :) – Marcel Mar 15 '11 at 08:46
  • Are you trying to get DI for unit testing where it is not actually deployed to an application server? If so I would as I recommended go for a simple approach and make the 2 "collaborators" protected methods and just inherit from the class and DI through that method instead of going the entire way toward something like Spring. That is actually what we did on our last project. – Shane Mar 15 '11 at 12:00
  • @sstarcher: thanks for your answer. you are correct. we currently have them declared as package private. from a testing point of view everything is fine and works well. _but_ i still need to know what is the best way to wire up the dependencies inside the container when the server is running? how i can mock and unit test is alredy clear to me :) setting up the "right" annotations for the deployed application (spring vs. guice vs. CDI vs. EJB) is the challenge. – Marcel Mar 15 '11 at 14:19
  • So your wondering what to do with the 2 collaborators in the deployed environment. @EJB is the correct way to wire the 2 collaborators that you have unless you have issue's that I don't know about. If you are already using stateless session beans I don't know why you would do anything other then contiune with stateless session beans for the collaborators. – Shane Mar 15 '11 at 17:48
  • @sstarcher: thanks again. we currently don't have anything yet. we are planning the new application. and we are wondering if all the collaborators should be stateless session beans. one consequence would be possibly multiple instances in the pool that will be created for each bean (or @Singleton/@Service(jboss)). is this a big overhead? it feels strange to have every single, tiny, little class beeing a stateless session bean. but i am also aware of "don't do premature optimization" unless you really have a performance bottle neck. any ideas or real world examples? – Marcel Mar 16 '11 at 09:34
  • It depends on what the classes are and what they are suppose to accomplish. If you are using EJB 3.1 you should have access to @Singleton, but not if you are only using EJB 3.0. Think of it as being multi-threaded, because each EJB that is created in the pool will be it's own thread. If you were to deploy the collaborators as singleton's you must make sure multi-threading is not a issue, but if you deploy the collaborators as EJB's then they will be pooled and only a single thread will access each EJB. Basically it comes down to design both options are valid. – Shane Mar 16 '11 at 12:00