I'm the creator of Hibernate, a popular object/relational persistence solution for Java, and Seam, an application framework for enterprise Java. I've also contributed to the Java Community Process standards as Red Hat representative for the EJB, JPA, JSF specifications and as spec lead of the CDI specification. At Red Hat, I'm currently working on Ceylon, a new programming language for the JVM.
I also post stuff on G+.
| Recent Entries |
|
20. Mar 2012
|
|
|
26. Feb 2012
|
|
|
10. Jan 2012
|
|
|
12. Aug 2011
|
|
|
11. Aug 2011
|
|
|
06. Aug 2011
|
|
|
02. Aug 2011
|
|
|
01. Aug 2011
|
|
|
24. Jul 2011
|
|
|
22. Jul 2011
|
|
|
21. Jul 2011
|
|
|
20. Jul 2011
|
|
|
19. Jul 2011
|
|
|
17. Jul 2011
|
|
|
13. Jul 2011
|
| Contexts and Dependency Injection | (44) |
| Ceylon | (43) |
| Web Beans | (41) |
| Seam News | (29) |
| Seam | (28) |
| Weld | (14) |
| Java EE 6 | (13) |
| Introduction to Ceylon | (12) |
| Hibernate | (6) |
| JavaServer Faces | (6) |
| JPA | (5) |
| JPA 2 | (5) |
| Web Beans Sneak Peek | (5) |
| Criteria Queries | (4) |
| Bean Validation | (3) |
| EE6 Wishlist | (3) |
| Portable Extensions | (3) |
| Seam Wiki | (3) |
| Web Frameworks | (3) |
| Interceptors | (2) |
| JBoss Tools | (2) |
| Payasos | (2) |
| XML Hell | (2) |
| Ceylon IDE | (1) |
| EJB | (1) |
| Granite DS | (1) |
| JDO | (1) |
| Persistence | (1) |
| Photography | (1) |
| RichFaces | (1) |
|
Java Persistence with Hibernate
with Christian Bauer November 2006 Manning Publications 841 pages (English), PDF ebook |
|
Hibernate in Action
with Christian Bauer August 2004 Manning Publications 408 pages (English), PDF ebook |
In reply to this post, Matt writes:
Where I still have a bit of trouble with this is if we implement each of the six EJB TransactionAttributeTypes with separate interceptors and bindings, and package them in a .jar file... I'm ok with having some kind of enablement in the beans.xml file for my .war, but to have the user enter all six interceptors is awkward for a library developer to force on someone...
For a couple of hours I thought he had me on this one, but it turns out that CDI has a fairly neat solution.
What Matt is trying to do is have a different annotation for each transaction propagation style, for example @RequiresTransaction, @RequiresNewTransaction, @MandatoryTransaction, etc, instead of having a single @Transactional annotation which specifies the propagation style using an annotation member. He's worried that CDI will force him to use a separate interceptor for each annotation, and then declare all these interceptor classes in beans.xml.
But there's a better way :-)
First, let's create an interceptor binding type that specifies the propagation style using a member. Note that we're not going to use this directly in our beans.
@Inherited
@InterceptorBinding
@Target({TYPE, METHOD})
@Retention(RUNTIME)
public @interface Transactional {
@Nonbinding
TransactionPropagation value() default REQUIRED;
}
Where TransactionPropagation is an enumeration of propagation styles:
public enum TransactionPropagation { REQUIRED, REQUIRES_NEW, MANDATORY, ... }
CDI interceptor bindings can be inherited by other interceptor bindings. This feature allows us to use our @Transactional annotation as a meta-annotation. So let's apply @Transactional to Matt's annotations, for example:
@Inherited
@Transactional(REQUIRED)
@InterceptorBinding
@Target({TYPE, METHOD})
@Retention(RUNTIME)
public @interface RequiresTransaction {}
@Inherited
@Transactional(REQUIRES_NEW)
@InterceptorBinding
@Target({TYPE, METHOD})
@Retention(RUNTIME)
public @interface RequiresNewTransaction {}
We use these interceptor bindings by annotating the bean class, for example:
@RequiresTransaction
public class Users {
@RequiresNewTransaction
public void login() { ... }
}
An annotation at the method level should override an annotation at the class level.
Now we can implement transaction management using a single interceptor class:
@Transactional @Interceptor
class TransactionInterceptor {
@AroundInvoke
public Object manageTransaction(InvocationContext ctx) throws Exception {
TransactionPropagation tp = getTransactionPropagation(ctx.getMethod());
...
}
/**
* Get the TransactionPropagation for the meta-annotation
*/
private TransactionPropagation getTransactionPropagation(Method m) {
//first look at method-level annotations, since they take priority
for (Annotation a: m.getAnnotations()) {
if (a.annotationType().isAnnotationPresent(Transactional.class)) {
return a.annotationType().getAnnotation(Transactional.class).value();
}
}
//now try class-level annotations
for (Annotation a: m.getDeclaringClass().getAnnotations()) {
if (a.annotationType().isAnnotationPresent(Transactional.class)) {
return a.annotationType().getAnnotation(Transactional.class).value();
}
}
return null;
}
}
This interceptor class that implements all of the transaction propagation styles. Neat, huh?
Matt Corey has blogged about CDI interceptor bindings, showing a simple example of how you can implement your own @RequiredTx annotation. He also lightly criticizes the use of beans.xml for interceptor enablement. (This was also discussed in the Weld forum.) I really think we have the design just right here, and I'll explain why. But first let me remember why CDI interceptor bindings are much better than the @Interceptors annotation from EJB 3.0.
In EJB 3.0, you could declare the interceptors of a bean by specifying them directly on the bean class. Using Matt's example:
public class UserGetterer {
@Interceptors({RequiredTxInterceptor.class, SecurityInterceptor.class})
public User loadUser() { ... }
}
Now, I count three problems with this:
- It's very ugly to have the bean class depend directly upon the interceptor implementation class.
- Interceptors should be able to vary depending upon the deployment environment - I don't need my transaction interceptor in tests, and I definitely don't want my security interceptor!
- The interceptor ordering is defined by the order that the interceptors are listed - which I suppose is fine if the interceptors are truly orthogonal, but this is rarely the case. Interceptor ordering should be defined more centrally, reducing the possibility for subtle bugs.
(EJB 3.0 also defined an XML-based approach to binding interceptors to beans, which is less problematic, but I prefer to see information like this in my code.)
So, in CDI, we introduce an indirection, called an interceptor binding. An interceptor binding is an annotation - you can see an example in Matt's post - that we use instead of the interceptor class:
public class UserGetterer {
@RequiredTx @Secure
public User loadUser() { ... }
}
Now, our bean class doesn't depend directly upon the interceptor implementation classes, and doesn't specify the ordering in which the interceptors are called. To specify the connection between the bean and the interceptor classes we need to do two more things:
- apply the interceptor bindings to the interceptor classes, and
- enable the interceptors by listing them in the beans.xml file of the bean's module.
Matt objects to the second requirement:
Yeah, I know -- it feels kind of like we're exposing your implementation detail by asking the user to enable the interceptor instead of the annotation... kind of annoying, but I can deal with it...
Well, not really - on the contrary, you're explicitly not doing that. The beans.xml file contains deployment-specific metadata - just the stuff that depends upon your deployment. So in your test environment, you don't specify any interceptors at all in beans.xml. In your production deployment you can enable RequiredTransactionInterceptor. In some other deployment, you can enable DummyRequiredTransactionInterceptor, a different implementation of the @RequiredTx semantic
or aspect
. It's even possible to bind multiple interceptors to the same interceptor binding! So we have truly decoupled the semantic annotation @RequiredTx from its implementation, RequiredTransactionInterceptor.
So we've got an extra level of indirection here that we would not have if it was the annotation we were specifying in beans.xml, as suggested by Matt.
In fact, beans.xml serves two different roles here. It lets you specify:
- any, or no, or multiple implementations of the interceptor binding, for the particular deployment, and
- the interceptor ordering.
Ordering is important. It's very likely that you'll be using interceptors defined by various different portable extensions in your application. These portable extensions don't know anything about each other, so they don't know what order they should be called in. We can't specify the interceptor ordering in the portable extensions that define the interceptors. It's your job, as application developer, to specify the ordering of these interceptors.
Matt says:
another thing to note is that if you pack your interceptors into a shareable library file, all other library files in your application will still need to do this, even if you enable it in your .jar file -- that's because there's no concept of a global interceptor in CDI, but to be safe, each library is forced to enable all interceptors in use, so that they can enforce the ordering of interceptors in a very intuitive manner... I can accept this reasoning simply because they have defined it, rather than letting it be an undefined mess, so again, it's more of annoyance for me -- hopefully there will be other options in the future...
OK, so let's step back a second. If my application is deployed as a single module, there is a global ordering, the ordering defined by the beans.xml file of that module. Now, back in Java EE 5 days, it wasn't possible to deploy an application that used EJBs as a single module. But it is now. A war can now directly contain EJBs. So single-module applications are going to be very common. So that's the simple case out of the way.
Now, for the more complex case of an application that really, truly needs to be deployed, for example, as an ear with multiple war and EJB jar modules, or as a war containing multiple jar modules, it's quite likely that the various modules are going to each define a different list of interceptors, decorators and alternatives. I mean, the whole point of modularizing the application is to decouple the modules.
I suppose I accept that we could allow toplevel
beans.xml file, that defined a global, or default, list of interceptors, decorators and alternatives. This would be very easy to add to the CDI spec, but I think it's a pretty advanced case. Historically, Java EE has not allowed you to put module-level metadata in the ear.
Matt Corey writes:
Whew, it's been a while since I've started looking at what's new in Java EE 6, partially because I've been fiddling with the newest addition to the Java EE portfolio -- JSR-299, aka CDI, f/k/a Web Beans, and this one could be big... Let's start with a bang -- CDI will eventually push EJB to obscurity...
The good news is that Matt seems to like CDI. The bad news is that for now there are questions out there about how CDI and the new managed beans spec affect the future of EJB.
Matt goes on to say:
CDI has the potential, I believe, to provide all of the most commonly used services that the EJB spec provides, and let's face it, this mean transactions, timers, asynchronous process with MDB's, and now Singleton Startup beans.
My take on this is a bit different. First of all, it's important to understand that there is no such thing as a CDI bean
. CDI applies to any managed bean. Some managed beans are EJBs. When we need to use the EJB services in a managed bean, we just add a @Stateless, @Stateful or @Singleton annotation, and away we go. Nevertheless, it doesn't seem necessary to require this lifecycle annotation if all we want to do is add declarative security or transaction management to a bean.
My view, for now, is that we can divide the functionality defined by the EJB spec into two categories:
- functionality which makes most sense for components which are entrypoints to the application - endpoints for remote invocations delivered via RMI, HTTP or message-oriented middleware, and
- functionality which should be available to beans which are part of the internal implementation of the application.
In the first category I include things like:
- the basic stateless/stateful/singleton lifecycle model, which has always made most sense for entrypoints,
- remote and web service endpoint interfaces, and
- message-driven beans.
In the second category, I would put:
- declarative concurrency management,
- declarative transaction management, and
- declarative security.
Even though these things are most useful at system entrypoints, they are also needed at a finer grain. And they're also needed for entrypoints which are not EJBs - for example, Servlets. So I think it's very likely that Java EE 7 will generalize these features to work for all Java EE components. That's certainly what we'll be arguing for.
If EE 7 does move in this direction, you'll be able to use plain managed beans in many cases which currently require EJB, and EJB itself will take on a clearer role in the EE architecture. EJB will be the spec with defines the programming model for remote and asynchronous invocation endpoints. It's likely that with this more focused identity, EJB will be a more manageable technology.
Of course, there's going to be couple of things which don't fit clearly in either category. The ones I'm most doubtful about are timers and asynchronous methods. These could, perhaps, be generalized to all managed beans, but it's not clear to me that there's a real need.
I've seen a couple of folks wondering why CDI requires a beans.xml file in every bean archive. If there's no alternatives, interceptors, or decorators to declare, why do you need to have the empty file?
Well, there's two things about CDI that we need to keep in mind:
- CDI does not require any special declaration for a Java class to be injected - that's right, no annotation or XML declaration at all!
- CDI does not define any special kind of module - CDI beans can be deployed in a library jar, EJB jar, war, rar, or JVM classpath directory.
The CDI specification calls the process of identifying beans in modules bean discovery.
So there are potentially a lot of classes in the classpath which might be beans! We don't want to force the container to scan every one of those classes at startup and build its internal metamodel for each of them. This really could make bean discovery very slow.
But there's another reason we need to give the user some control over which classes are available for injection. We don't want every class in the classpath to potentially match an injection point, including classes that were never intended to be injected into things. This would force the developer to have to use qualifiers much more often to disambiguate injection points.
So we have two choices. We could have the developer:
- explicitly exclude modules which do not contain beans, or
- explicitly declare modules which do contain beans.
I think it's clear that the second option is a much better way to go. Thus, CDI has the notion of a bean archive. A bean archive is just a module that has a file named beans.xml in the metadata directory. The container looks for beans in bean archives. It ignores other modules.
Now, you might be wondering if we've got the granularity wrong here. Why should module be the right criteria to use for including/excluding a class. Why not consider:
- a class-level annotation,
- the package,
- some type it implements or extends, or
- some naming convention.
Well, I think we've got the first option covered. Annotate a bean @Alternative, or with an alternative stereotype, and it will be considered disabled by CDI, as long as you don't explicitly enable it in beans.xml. That's not quite the same thing as excluding the class from scanning altogether, but it's close. (One difference is that a portable extension with still get a ProcessAnnotatedType event for that class.)
Excluding a package makes sense to me, and a future version of CDI might allow you to declare excluded packages in beans.xml.
Excluding a bean by type or naming convention doesn't appeal to me at all. In the world of CDI, we use stereotypes for identifying architectural roles. We don't use marker interfaces or naming conventions. I strongly disapprove of having names affect functionality.
We'll experiment with giving you some finer grained control over bean discovery in Weld. However, my expectation is that the current solution is going to work great for most people.
DZone recently interviewed me about CDI and Weld. Please, no more jokes about the hat. I had a horrid morning that day and had to run off to the interview without a shower, breakfast or coffee.
|
|
|
Showing 6 to 10 of 38 blog entries tagged 'Contexts and Dependency Injection' |
|
|