CDI 和 EJB 如何比较? 如何交互?

我很难理解这两者是如何相互作用的以及它们之间的界限在哪里。有重叠吗?它们之间是否有冗余?

我知道两者都有相关的注释,但是我还没有找到一个包含简短描述的完整列表。不确定这是否有助于澄清它们之间的差异或重叠之处。

真的很困惑。我(认为我)相当理解 EJB,我想我很难确切地理解 CDI 带来了什么,以及它如何取代或增强 EJB 已经提供的功能。

45705 次浏览

CDI: it is about dependency injection. It means that you can inject interface implementation anywhere. This object can be anything, it can be not related to EJB. Here is an example of how to inject random generator using CDI. There is nothing about EJB. You are going to use CDI when you want to inject non-EJB services, different implementations or algorithms (so you don't need EJB there at all).
EJB: you do understand, and probably you are confused by @EJB annotation - it allows you to inject implementation into your service or whatever. The main idea is that class, where you inject, should be managed by EJB container. Seems that CDI does understand what EJB is, so in Java EE 6 compliant server, in your servlet you can write both

@EJB EJBService ejbService;

and

@Inject EJBService ejbService;

that's what can make you confusing, but that's probably the only thing which is the bridge between EJB and CDI.

When we are talking about CDI, you can inject other objects into CDI managed classes (they just should be created by CDI aware frameworks).

What else CDI offers... For instance, you use Struts 2 as MVC framework (just example), and you are limited here, even using EJB 3.1 - you can't use @EJB annotation in Struts action, it is not managed by container. But when you add Struts2-CDI plugin, you can write there @Inject annotation for the same thing (so no more JNDI lookup needed). This way it enhances EJB power, but as I mentioned before, what you inject with CDI - it does not matter if it is related to EJB or not, and that's its power.

PS. updated link to the example

It is currently indeed a bit confusing as there are now multiple component models in Java EE. They are CDI, EJB3 and JSF Managed Beans.

CDI is the new kid on the block. CDI beans feature dependency injection, scoping and an event bus. CDI beans are the most flexible with respect to injection and scoping. The event bus is very lightweight and very well suited for even the simplest of web applications. In addition to this, CDI also exposes a very advanced feature called portable extensions, which is a kind of plug-in mechanism for vendors to provide extra functionality to Java EE that can be made available on all implementations (Glassfish, JBoss AS, Websphere, etc).

EJB3 beans were retrofitted from the old legacy EJB2 component model* and were the first beans in Java EE to be managed beans via an annotation. EJB3 beans feature dependency injection, declarative transactions, declarative security, pooling, concurrency control, asynchronous execution and remoting.

Dependency injection in EJB3 beans is not as flexible as in CDI beans and EJB3 beans have no concept of scoping. However, EJB3 beans are transactional and pooled by default**, two very useable things that CDI has chosen to leave in the domain of EJB3. The other mentioned items are also not available in CDI. EJB3 has no event bus of its own though, but it does have a special type of bean for listening to messages; the message driven bean. This can be used to receive messages from the Java Messaging System or from any other system that has a JCA resource adaptor. Using full blown messaging for simple events is far more heavyweight than the CDI event bus and EJB3 only defines a listener, not a producer API.

JSF Managed Beans have existed in Java EE ever since JSF was included. They too feature dependency injection and scoping. JSF Managed Beans introduced the concept of declarative scoping. Originally the scopes were rather limited and in the same version of Java EE where EJB3 beans could already be declared via annotations, JSF Managed Beans still had to be declared in XML. The current version of JSF Managed Beans are also finally declared via an annotation and the scopes are expanded with a view scope and the ability to create custom scopes. The view scope, which remembers data between requests to the same page is a unique feature of JSF Managed Beans.

Apart from the view scope, there is very little still going for JSF Managed Beans in Java EE 6. The missing view scope in CDI there is unfortunate, since otherwise CDI would have been a perfect super set of what JSF Managed Beans offer. Update: In Java EE 7/JSF 2.2 a CDI compatible @ViewScoped has been added, making CDI indeed that perfect super set. Update 2: In JSF2.3 the JSF managed beans have been deprecated in favour of CDI managed beans.

With EJB3 and CDI the situation is not that clear cut. The EJB3 component model and API offers a lot of services that CDI does not offer, so typically EJB3 cannot be replaced by CDI. On the other hand, CDI can be used in combination with EJB3 - e.g. adding scope support to EJBs.

Reza Rahman, expert group member and implementor of a CDI implementation called CanDI, has frequently hinted that the services associated with the EJB3 component model can be retrofitted as a set of CDI annotations. If that were to happen, all managed beans in Java EE could become CDI beans. This does not mean that EJB3 disappears or becomes obsolete, but just that its functionality will be exposed via CDI instead of via EJB's own annotations like @Stateless and @EJB.

Update

David Blevins of TomEE and OpenEJB fame explains the differences and similarities between CDI and EJB very well on his blog: CDI, when to break out the EJBs

* Although it's just an increment in version number, EJB3 beans were for the most part a completely different kind of bean: a simple pojo that becomes a "managed bean" by applying a simple single annotation, vs the model in EJB2 where a heavyweight and overly verbose XML deployment descriptor was required for each and every bean, in addition to the bean being required to implement various extremely heavyweight and for the most part meaningless component interfaces.

** Stateless session beans are typically pooled, stateful session beans typically not (but they can be). For both types pooling is thus optional and the EJB spec does not mandate it either way.

Albert Einstein: If you can't explain it simply, you don't understand it well enough

Ejbs and CDI are pretty simple to understand.

Ejbs:

  1. Will always be annotated by scope qualifiers, for instance, @Stateless, @Stateful, @Request etc
  2. The instances of Ejbs is controlled by the Java EE framework and pooled. It is the duty of EE framework to provide the instances for the consumer.

@Stateless

 public class CarMaker(){
public void createCar(Specification specs){
Car car = new Car(specs);
}
}

The CarMaker is Annotated with specific Ejbs scope, therefore, it's Ejb

CDI:

  1. Not managed entirely by EE framework, instances has to be created by yourself.
  2. It is always dependent. let me explain "Dependent" with example:

    class Specification { private String color; private String model; //- Getter and Setter }

The Specification class is CDI, since it is not annotated with Ejb scopes and also this has to initialized by your code not EE framework. One point to be noted here is that since we didn't Annotated the Specification class, it is by default Annotated by @Dependent annotation.

@Dependent  <- By default added
class Specification { ... }

Further reading: You need to study more between Ejbs scope annotation and CDI scope annotation, that will further clear the conceptl