现在的位置: 首页 > 综合 > 正文

New features in EJB3.1 (Part 4)

2013年09月02日 ⁄ 综合 ⁄ 共 13549字 ⁄ 字号 评论关闭

 作者:Reza Rahman  文章来源:www.theserverside.com

In the first three articles of this series, I covered optional interfaces
for Session beans, Singleton beans, EJB Timer Service enhancements, simplified
packaging, asynchronous Session bean invocation and EJB Lite. By popular demand,
in this article I will cover WebBeans/EJB 3.1 integration. Remember, none of
this has been finalized yet. All of this is really just a peek into the inner
workings of the JCP so that you have a chance to provide feedback.

WebBeans and EJB: Together Forever

WebBeans is one of the most exciting JSRs being developed in the Java EE 6
timeframe. The basic value proposition of WebBeans is actually pretty intuitive.
If you have developed an application or two using JSF and EJB 3.0, you may
have noticed that the JSF backing bean layer is usually pretty thin. In fact,
even though you can easily inject EJBs into backing beans using the @EJB annotation,
it’s not too far off to classify backing beans as glue-code. WebBeans
eliminates this glue-code by allowing you to directly use EJBs as JSF backing
beans. We’ll see how great this actually looks in a second.

In addition to effectively integrating the JSF and EJB programming models,
WebBeans also adds a number of very cool features including robust annotation-driven
DI, further ease-of-use for using the Java EE interceptor model as well as
sensible component context management for web applications. This last feature
I won’t talk about in great detail since it is requires more of a JSF
focus than an EJB focus, but I’ll cover the rest.

WebBeans is largely inspired by JBoss Seam as well as Google Guice. The JSR
is being led by Gavin King and Bob Lee is part of the expert group. My guess
is that the core Seam code is going to be the basis for the major WebBeans
pluggable implementation although it looks like many application servers like
Caucho Resin will provide their own implementation as well.

EJBs as JSF Backing Beans

Let’s see what WebBeans is all about by re-factoring an example from EJB
3 in Action
. The first substantial Session bean example in EJB 3
in Action
is used for adding a bid. The session bean uses JPA to save
a Bid entity into the database. Here is how the session bean and the entity
would look like in a WebBeans environment:

  1. @Component  
  2. @Stateless  
  3. @Named("placeBid")  
  4. public class PlaceBidBean {  
  5.     @PersistenceContext  
  6.     private EntityManager entityManager;  
  7.       @In  
  8.       private Bid bid;  
  9.     public void addBid() {  
  10.         entityManager.persist(bid);  
  11.     }  
  12. }  
  13. @Component  
  14. @Entity  
  15. @Named("bid")  
  16. public class Bid {  
  17.     private Long bidId;  
  18.     private String bidder;  
  19.     private String item;  
  20.     private Double bidPrice;  
  21.     @Id  
  22.     @GeneratedValue  
  23.     public Long getBidId() {  
  24.         return bidId;  
  25.     }  
  26.     public void setBidId(Long bidId) {  
  27.         this.bidId = bidId;  
  28.     }  
  29.     public String getBidder() {  
  30.         return bidder;  
  31.     }  
  32.     public void setBidder(String bidder) {  
  33.         this.bidder = bidder;  
  34.     }  
  35.     public String getItem() {  
  36.         return item;  
  37.     }  
  38.     public void setItem(String item) {  
  39.         this.item = item;  
  40.     }  
  41.     public Double getBidPrice() {  
  42.         return bidPrice;  
  43.     }  
  44.     public void setBidPrice(Double bidPrice) {  
  45.         this.bidPrice = bidPrice;  
  46.     }  
  47. }  

The @Component annotation on both the PlaceBidBean stateless session bean
and the Bid JPA entity registers these components with the WebBeans container.
@Named annotation assigns names to the components that the WebBeans container
knows them by. These names are then used in JSF pages to refer to the components.
The @In annotation on the bid instance variable injects a Bid entity into the
session bean. It’ll be clearer how this works when you look at the JSP
code below that uses the WebBeans components. Figure 1 depicts how the page
actually looks like to the bidder adding the bid.

  1. <html>  
  2.   ...  
  3.   <body>  
  4.     <f:view>  
  5.       ...  
  6.       <h:form>  
  7.         <table>  
  8.           <tr>  
  9.             <td>Bidder</td>  
  10.             <td><h:inputText value="#{bid.bidder}"/></td>  
  11.           </tr>  
  12.           <tr>  
  13.             <td>Item</td>  
  14.             <td><h:inputText value="#{bid.item}"/></td>  
  15.           </tr>  
  16.           <tr>  
  17.             <td>Bid Amount</td>  
  18.             <td><h:inputText value="#{bid.bidPrice}"/></td>  
  19.           </tr>  
  20.         </table>  
  21.         ...  
  22.         <h:commandButton type="submit" value="Add Bid"   
  23.             action="#{placeBid.addBid}"/>  
  24.         ...  
  25.       </h:form>  
  26.       ...  
  27.     </f:view>  
  28.   </body>  
  29. </html>  

Figure 1: Add Bid Page

As you can see, the bidder, item and bid amount fields in the JSP are bound
to the corresponding properties of the Bid entity through EL. The names “bid" and “placeBid" in
the EL match the values of the @Named annotation placed on the components.
When WebBeans first encounters the bean name corresponding to the Bid entity,
it creates a new instance of the entity behind the scenes and places it in
the underlying page request context. Notice also that the PlaceBidBean.addBid
method is bound as the action listener for the button to add the bid. When
the button is clicked and the underlying form is submitted, WebBeans binds
the values of the form fields to the Bid entity properties. It then injects
the populated entity into the bid instance variable of the PlaceBidBean session
bean because of the @In annotation. Unlike the Bid entity, the EJB is looked
up from JNDI and placed into the request context. When the addBid method is
invoked to handle the button click, the EJB uses the JPA entity manager to
save the injected entity. Other than the request context, WebBeans also understands
the application, session and very innovative “conversation" contexts.
For details of these contexts, check out the WebBeans draft specification.

The appeal of the WebBeans programming model in the code above really cannot
be understated. WebBeans unifies JSF, EJB and JPA in a way that makes Java
EE really feel like one seamlessly integrated platform that just works out
of the box and minimizes boilerplate code, much like what you might be used
to while working with frameworks like Ruby on Rails. What do you think? Do
you think this is compelling? Can you see any pitfalls to this model?

WebBeans
Dependency Injection

A large majority of enterprise application components are either service components,
DAOs or domain model components. While JPA is ideal for implementing domain
model components, service and DAO components are good candidates for EJB. This
is because EJBs are transactional and thread-safe by default (a lot of people
seem to have the misconception that EJBs are remote-enabled by default as well;
this is not true). EJB is even more of an obvious component model if you might
use declarative services for security, remoting, web services, messaging, scheduling
or asynchronous processing. These services are at our fingertips in the form
of decorating an EJB with an annotation or two as needed.

However, there are some components in an application that simply don’t
need declarative services, don’t need to be transaction-aware and don’t
need implicit thread-safety guarantees. Good examples of such components are
utilities or helper components. Because EJB 3.0 did not support dependency
injection for non-managed components, it was not possible to use DI for such
components without making them EJBs. WebBeans dependency injection solves these
problems because the @Component annotation can be applied to any POJO, not
just EJBs and JPA entities. Just as the @In annotation was used to inject the
Bid entity into the PlaceBidBean stateless session bean, WebBeans can also
inject plain components into EJBs.

Let’s take a look at a quick example. Let’s assume that the bid
amount entered by the user is rounded up to two decimal places using a utility
class before the bid is saved. This can be done as follows:

  1. @Component  
  2. public class MathUtil {  
  3.     ...  
  4.     public static double round(double value, int decimalPlaces) {  
  5.         BigDecimal converter = new BigDecimal(Double.toString(value));  
  6.         converter = converter.setScale(decimalPlaces,   
  7.             BigDecimal.ROUND_HALF_UP);  
  8.         return converter.doubleValue();  
  9.     }  
  10.     ...  
  11. }  
  12. @Component  
  13. @Stateless  
  14. @Named("placeBid")  
  15. public class PlaceBidBean {  
  16.     @PersistenceContext  
  17.     private EntityManager entityManager;  
  18.       @In  
  19.       private Bid bid;  
  20.       @In  
  21.       private MathUtil mathUtil;  
  22.         public void addBid() {  
  23.           bid.setBidPrice(mathUtil.round(bid.getBidPrice(), 2));  
  24.             entityManager.persist(bid);  
  25.     }  
  26. }  

In this case, a new instance of MathUtil will be created and injected into
the EJB as needed. Although plain WebBeans components cannot directly use EJB
declarative services, they can use DI themselves, as well as life-cycle callbacks
( @PostConstruct/ @PreDestroy) and interceptors.

The @In and @Component annotations are really just the tip of the ice-berg.
WebBeans brings a whole host of other DI features into Java EE, including Guice
style producer methods and binding annotations. Note that all EJB types including
message driven beans can use WebBeans features.

WebBeans Interceptor Enhancements

Another major WebBeans feature very relevant to EJB is a very cool extension
to the existing interceptor model. You can currently apply interceptors to
EJBs using the @Interceptor and @Interceptors annotations. While this structure
is both pretty easy to understand and intuitive, it is not very flexible. WebBeans
introduces a little more flexibility to interceptors without making things
more complex by introducing an annotation-based indirection. The easiest way
to understanding this is though code. Let’s assume that we want to apply
an auditing interceptor to the PlaceBidBean EJB. This is how we could do it:

  1. @InterceptorBindingType  
  2. @Target({TYPE, METHOD})  
  3. @Retention(RUNTIME)  
  4. public @interface Audited {}  
  5. @Audited @Interceptor  
  6. public class AuditInterceptor {  
  7.     @AroundInvoke  
  8.     public Object audit(InvocationContext context) throws Exception {  
  9.         System.out.println("Entering: "  
  10.             + context.getMethod().getName());  
  11.         System.out.println("  with args: "  
  12.             + context.getParameters());  
  13.         return context.proceed();  
  14.     }  
  15. }  
  16. @Component  
  17. @Stateless  
  18. @Named("placeBid")  
  19. public class PlaceBidBean {  
  20.     @PersistenceContext  
  21.     private EntityManager entityManager;  
  22.       @In  
  23.       private Bid bid;  
  24.       @Audited  
  25.     public void addBid() {  
  26.         entityManager.persist(bid);  
  27.     }  
  28. }  

The @InterceptorBindingType annotation on the @Audited annotation is used
to declare the fact that it is to be bound to an interceptor. Unlike the EJB
3.0 interceptor model, WebBeans uses the @Interceptor annotation to bind one
or more annotations to a given interceptor. So the @Audited and @Interceptor
annotations placed on AuditInterceptor means that the @Audited annotation placed
on a component or method binds it to the interceptor. As a result, when the
placeBid method is invoked, the AuditInterceptor is triggered and the audit
method executes.

In addition to adding a level of indirection and flexibility, I think this
extension really improves code readability. What do you think? Should this
extension be adopted into the EJB specification itself or be applied to Java
EE as a whole?

Still in the Works

Activity on the expert groups had understandably slowed down a bit due to
JavaOne. However, things are picking back up strongly again. There are still
a number of very interesting topics that are being actively discussed:

  1. The standardization of JNDI mappings is being simultaneously discussed
    in the Java EE 6 and EJB 3.1 expert groups. Looks like some very neat things
    will happen very soon in this area.
  2. Support for using EJB 3.1 in Java SE environments (e.g. unit tests) is
    still in the works. The fact that Embedded GlassFish has followed the OpenEJB,
    EasyBeans and Embedded JBoss path is a strong indication to me that this
    is solidly on track.
  3. A great extensibility mechanism proposal is being discussed in the Java
    EE 6 expert group. Looks like this might eventually end up in the EJB expert
    group as well. If this goes through, it will be a breeze to add non-standard
    third party declarative, annotation-based services to Java EE.

What are your thoughts on these features? If you think they are important,
voice your opinion by emailing the expert groups. The EJB 3.1 expert group
email address is jsr-318-comments@jcp.org while
the WebBeans expert group email address is jsr-299-comments@jcp.org.
Feel free to copy me at reza@rahmannet.net.
In the meanwhile, I’ll keep you informed as things settle down on the
remaining features in the next and possibly last article in this series.

References

  1. JSR 316: Java EE 6, http://jcp.org/en/jsr/detail?id=316.
  2. JSR 318: Enterprise JavaBeans 3.1, http://jcp.org/en/jsr/detail?id=318.
  3. JSR 299: Web Beans, http://jcp.org/en/jsr/detail?id=299.
  4. Seam, http://www.seamframework.org.
  5. Google Guice, http://code.google.com/p/google-guice/.

抱歉!评论已关闭.