CDI does support direct field injection, initializer method parameter injection and constructor parameter injection. From the CDI 1.0 specification:
3.7. Bean constructors
When the container instantiates a bean
class, it calls the bean
constructor. The bean constructor is
a constructor of the bean class.
The application may call bean
constructors directly. However, if the
application directly instantiates the
bean, no parameters are passed to the
constructor by the container; the
returned object is not bound to any
context; no dependencies are injected
by the container; and the lifecycle of
the new instance is not managed by the
container.
3.7.1. Declaring a bean constructor
The bean constructor may be identified
by annotating the constructor
@Inject
.
@SessionScoped
public class ShoppingCart implements Serializable {
private User customer;
@Inject
public ShoppingCart(User customer) {
this.customer = customer;
}
public ShoppingCart(ShoppingCart original) {
this.customer = original.customer;
}
ShoppingCart() {}
...
}
@ConversationScoped
public class Order {
private Product product;
private User customer;
@Inject
public Order(@Selected Product product, User customer) {
this.product = product;
this.customer = customer;
}
public Order(Order original) {
this.product = original.product;
this.customer = original.customer;
}
Order() {}
...
}
If a bean class does not explicitly
declare a constructor using @Inject
,
the constructor that accepts no
parameters is the bean constructor.
If a bean class has more than one
constructor annotated @Inject
, the
container automatically detects the
problem and treats it as a definition
error.
If a bean constructor has a parameter
annotated @Disposes
, or @Observes
,
the container automatically detects
the problem and treats it as a
definition error.
A bean constructor may have any number
of parameters. All parameters of a
bean constructor are injection points.
Best Answer
Yes, you can freely mix both CDI and EJB and achieve some great results. It sounds like you are using
@WebService
and@Schedule
, which are good reasons for adding EJB to the mix.There's a lot of confusion out there, so here is some general information on EJB and CDI as they relate to each together.
EJB >= CDI
Note that EJBs are CDI beans and therefore have all the benefits of CDI. The reverse is not true (yet). So definitely don't get into the habit of thinking "EJB vs CDI" as that logic really translates to "EJB+CDI vs CDI", which is an odd equation.
In future versions of Java EE we'll be continuing to align them. What aligning means is allowing people to do what they already can do, just without the
@Stateful
,@Stateless
or@Singleton
annotation at the top.EJB and CDI in Implementation Terms
Ultimately, EJB and CDI share the same fundamental design of being proxied components. When you get a reference to an EJB or CDI bean, it isn't the real bean. Rather the object you are given is a fake (a proxy). When you invoke a method on this fake object, the call goes to the container who will send the call through interceptors, decorators, etc. as well as take care of any transaction or security checks. Once all that is done, the call finally goes to the real object and the result is passed back through the proxy to the caller.
The difference only comes in how the object to be invoked is resolved. By "resolved" we simply mean, where and how the container looks for the real instance to invoke.
In CDI the container looks in a "scope", which will basically be a hashmap that lives for a specific period of time (per request
@RequestScoped
, per HTTP Session@SessionScoped
, per application@ApplicationScoped
, JSF Conversation@ConversationScoped
, or per your custom scope implementation).In EJB the container looks also into a hashmap if the bean is of type
@Stateful
. An@Stateful
bean can also use any of the above scope annotations causing it to live and die with all the other beans in the scope. In EJB@Stateful
is essentially the "any scoped" bean. The@Stateless
is basically an instance pool -- you get an instance from the pool for the duration of one invocation. The@Singleton
is essentially@ApplicationScoped
So in a fundamental level, anything you can do with an "EJB" bean you should be able to do with a "CDI" bean. Under the covers it's awfully hard to tell them apart. All the plumbing is the same with the exception of how instances are resolved.
They aren't currently the same in terms of the services the container will offer when doing this proxying, but as I say we're working on it at the Java EE spec level.
Performance note
Disregard any "light" or "heavy" mental images you may have. That's all marketing. They have the same internal design for the most part. CDI instance resolution is perhaps a bit more complex because it is slightly more dynamic and contextual. EJB instance resolution is fairly static, dumb and simple by comparison.
I can tell you from an implementation perspective in TomEE, there's about zero performance difference between invoking an EJB vs invoking a CDI bean.
Default to POJOs, then CDI, then EJB
Of course don't use CDI or EJB when there is no benefit. Throw in CDI when you start to want injection, events, interceptors, decorators, lifecycle tracking and things like that. That's most the time.
Beyond those basics, there are a number of useful container services you only have the option to use if you make your CDI bean also an EJB by adding
@Stateful
,@Stateless
, or@Singleton
on it.Here's a short list of when I break out the EJBs.
Using JAX-WS
Exposing a JAX-WS
@WebService
. I'm lazy. When the@WebService
is also an EJB, you don't have to list it and map it as a servlet in theweb.xml
file. That's work to me. Plus I get the option to use any of the other functionality mentioned below. So it's a no-brainer for me.Available to
@Stateless
and@Singleton
only.Using JAX-RS
Exposing a JAX-RS resource via
@Path
. I'm still lazy. When the RESTful service is also an EJB, again you get automatic discovery and don't have to add it to a JAX-RSApplication
subclass or anything like that. Plus I can expose the exact same bean as an@WebService
if I want to or use any of the great functionality mentioned below.Available to
@Stateless
and@Singleton
only.Startup logic
Load on startup via
@Startup
. There is currently no equivalent to this in CDI. Somehow we missed adding something like anAfterStartup
event in the container lifecycle. Had we done this, you simply could have had an@ApplicationScoped
bean that listened for it and that would be effectively the same as an@Singleton
with@Startup
. It's on the list for CDI 1.1.Available to
@Singleton
only.Working in Parallel
@Asynchronous
method invocation. Starting threads is a no-no in any server-side environment. Having too many threads is a serious performance killer. This annotation allows you to parallelize things you do using the container's thread pool. This is awesome.Available to
@Stateful
,@Stateless
and@Singleton
.Scheduling work
@Schedule
orScheduleExpression
is basically a cron orQuartz
functionality. Also very awesome. Most containers just use Quartz under the covers for this. Most people don't know, however, that scheduling work in Java EE is transactional! If you update a database then schedule some work and one of them fails, both will automatically cleaned up. If theEntityManager
persist call fails or there is a problem flushing, there is no need to un-schedule the work. Yay, transactions.Available to
@Stateless
and@Singleton
only.Using EntityManagers in a JTA transaction
The above note on transactions of course requires you to use a
JTA
managedEntityManager
. You can use them with plain "CDI", but without the container-managed transactions it can get really monotonous duplicating theUserTransaction
commit/rollback logic.Available to all Java EE components including CDI, JSF
@ManagedBean
,@WebServlet
,@WebListener
,@WebFilter
, etc. The@TransactionAttribute
annotation, however, is available to@Stateful
,@Stateless
and@Singleton
only.Keeping JTA managed
EntityManager
The
EXTENDED
managedEntityManager
allows you to keep anEntityManager
open betweenJTA
transactions and not lose the cached data. Good feature for the right time and place. Use responsibly :)Available to
@Stateful
only.Easy synchronization
When you need synchronization, the
@Lock(READ)
and@Lock(WRITE)
annotations are pretty excellent. It allows you to get concurrent access management for free. Skip all the ReentrantReadWriteLock plumbing. In the same bucket is@AccessTimeout
, which allows you to say how long a thread should wait to get access to the bean instance before giving up.Available to
@Singleton
beans only.