楼主: Sky-Tiger

EJB 3: From legacy technology to secret weapon

[复制链接]
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
11#
 楼主| 发表于 2008-10-30 09:36 | 只看该作者
You can maintain the relation between the injected EntityManager and its persistence unit without recompiling the session bean, which is especially useful for local tests. On the other hand, the deployment descriptor is an additional artifact that you must create and maintain, so this approach is not free. Refactoring, especially, can be challenging, because the IDE must keep the source and XML configuration consistent.

For static resolution, annotations are more appropriate and efficient. You can easily set the persistence unit's name in the @PersistenceContext annotation, as in Listing 13. No additional deployment descriptors are required for this purpose.
Listing 13. Specifying the unit name with annotations.

@Stateless
public class BookServiceAnnotationBean implements BookService {

@PersistenceContext(unitName="DaC")
private EntityManager em;

public void create(Book book) {
this.em.persist(book);
}
}

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
12#
 楼主| 发表于 2008-10-30 09:37 | 只看该作者
Injecting resources

The injection of resources works slightly differently, although the principle is the same. DataSources, JMS resources, or mail Sessions are injected using the @Resource annotation, as shown in Listing 14.
Listing 14. Injecting resources from JNDI

@Stateless
public class DataSourceInjectionBean implements DataSourceInjection {
@Resource(mappedName = "mail/Context")
private Session mailContext;

@Resource(mappedName = "jms/Queue")
private Queue queue;
@Resource(mappedName = "jms/ConnectionFactory")
private ConnectionFactory eocFactory;

@Resource(name="jdbc/sample")
private DataSource ds;

public void accessResources(){
//use the datasource
}

}

The deployed resources are uniquely identified by the JNDI name, which can be used for injection, instead of "traditional" lookup. You can use the mappedName attribute for this purpose, although it is just a suggestion in the EJB specification and not mandatory behavior.

You can introduce additional indirection with the name attribute (see the DataSource in Listing 14), which can be resolved later in the application server specific deployment descriptor. Especially in this case, remember to "keep it simple." Every indirection costs you additional effort, which can be overwhelming at the end. Just think of all the overconfigured J2EE projects you've seen.

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
13#
 楼主| 发表于 2008-10-30 09:37 | 只看该作者
Interceptors

EJB 3 also gives you a way to do lightweight aspect-oriented programming (AOP). The principle of AOP is as simple as the principle of DI. The idea behind AOP is strict separation between pure business logic and nonfunctional code. You provide the nonfunctional code -- the aspects -- once and reuse it in different places. The reuse, however, happens externally, in the sense that the business-logic classes do not even know that they are decorated with additional functionality. In fact AOP could be explained as a flexible and configurable decorator that can be applied to methods, attributes, or constructors in declarative manner.

The EJB container comes with some built-in, highly reusable aspects. The availability of remote EJBs via SOAP-based Web services, RESTful services, or even Internet Inter-ORB Protocol (IIOP) remoting is nothing other than decoration of existing functionality with the crosscutting aspect of "remoting." Transaction and exception handling, security, concurrency, state management, and even persistence are classical aspects that the J2EE platform has supported from the beginning -- long before the term AOP became popular. Application-defined aspects were introduced with the EJB 3.0 specification. Before then, only the Web container could intercept incoming requests with the servlet filter.

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
14#
 楼主| 发表于 2008-10-30 09:37 | 只看该作者
In a well-designed Java EE application, session beans implement the major portion of business logic. This logic is functional or even procedural. Session beans are the natural place for the use of AOP ideas. Session beans mainly consist of methods and a default constructor. Attributes are very rare and mostly used in stateful session beans. All other attributes are not client specific and are shared by all instances. References to EntityManager, JMS resources, or other EJBs are typical examples for such technical state.

The Java EE aspects are called interceptors. Comparing them to fully fledged AOP frameworks is not accurate, because they are optimized for use with EJBs and so are rather limited. An EJB interceptor can be applied only to a particular EJB's methods. You can't apply interceptors to constructor invocations or attribute access. Interceptors are nevertheless absolutely sufficient for the most common use cases. You can enable an interceptor either with an annotation or in a deployment descriptor. (In this respect, interceptors are conceptually identical to the DI approach.)

An EJB 3 interceptor is just a Java class with one annotated method, as in Listing 15:
Listing 15. A tracing interceptor

public class TracingInterceptor {
@AroundInvoke
public Object trace(InvocationContext invocationContext) throws Exception{
System.out.println("Method: " + invocationContext.getMethod());
return invocationContext.proceed();
}
}

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
15#
 楼主| 发表于 2008-10-30 09:37 | 只看该作者
The actual call to the EJB is performed after the interceptor's execution. The interceptor has full control of the execution. It can invoke the method several times, change the parameters and return values, transform exceptions, and so on. The implementation of the interceptor is independent of the business logic. You activate an interceptor for a particular EJB by using the @Interceptors annotation, as in Listing 16:
Listing 16. Declaring an interceptor using an annotation

@Stateless
@Interceptors({TracingInterceptor.class, PerformanceMeasurement.class})
public class HelloBean implements Hello {

public String sayHello() {
return "Hello from Bean";
}
}

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
16#
 楼主| 发表于 2008-10-30 09:38 | 只看该作者
The annotation's value is an array of classes. The array's order is equivalent to the interception order.

Declaration of interceptors with annotations is convenient because it can fully leverage IDE support. Because the @Interceptors annotation refers to the interceptors as classes and not as Strings, your IDE and the compiler provide a higher comfort level by ensuring consistency and providing auto-completion.

On the other hand, because the interceptors are declared in the business code, every change requires recompilation and redeployment of the whole application. This could become a problem for "utility" interceptors that are only needed in the development phase or only activated for troubleshooting.

Fortunately, you can declare and apply interceptors in the standard deployment descriptors as well, as in Listing 17:
Listing 17. Declaring an interceptor in the XML deployment descriptor

<ejb-jar ...>
<!-- declaration (needed once) -->
   <interceptors>
      <interceptor>
         <interceptor-class>...PerformanceMeasurement</interceptor-class>
      </interceptor>
   </interceptors>

<!-- interceptor activation -->
   <assembly-descriptor>
      <interceptor-binding>
         <ejb-name>HelloBean</ejb-name>
            <interceptor-order>
               <interceptor-class>...PerformanceMeasurement</interceptor-class>
            </interceptor-order>
      </interceptor-binding>
   </assembly-descriptor>
</ejb-jar>

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
17#
 楼主| 发表于 2008-10-30 09:38 | 只看该作者
The first part of the configuration in Listing 17 is the actual declaration of the interceptor. It is needed only once. In the second part, the already declared interceptor can be applied to all beans from the ejb-jar, a particular bean, or even a specific, overloaded method.

The XML configuration is not only more flexible but also more powerful. Only in the deployment descriptor can you apply "default" interceptors that can intercept all beans in the module. But you should have additional good reasons for introducing XML deployment descriptors. They are harder to create and maintain. The XML configuration must be versioned together with source code; it's equally important and must be maintained with the same care. And although the application is more flexible and configurable with externalized XML configuration, this advantage loses its importance after deployment. No one will change the XML configuration in production without a test phase, so the additional flexibility is useful only in the development phase.

Another argument for the annotation-driven approach is the lower amount of "magic." The relation between the main concern (the session bean) and the cross-cutting concern (the interceptor) is self-documented. Refactoring of the interceptor -- such as renaming or moving it to other package -- can be performed in any average IDE without specific Java EE or EJB support.

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
18#
 楼主| 发表于 2008-10-30 09:38 | 只看该作者
Versatility of interceptors

Interceptors are not just POJOs; they come with some interesting features. They participate in transactions and support DI. So an interceptor can even use the functionality of another EJB directly, via DI, as the auditing code in Listing 18 does.
Listing 18. Injecting an EJB into an interceptor

public class AuditInterceptor {

@EJB
private Audit audit;

@AroundInvoke
public Object trace(InvocationContext invocationContext) throws Exception{
String info = ("Method: " + invocationContext.getMethod() + "\n");
info += ("Object: " + invocationContext.getTarget().getClass().getName());
this.audit.audit(info);
return invocationContext.proceed();
}
}

This feature makes it convenient to access an EJB's existing logic with the services it provides, such as transactions, concurrency, or security. This DI itself can be configured in the same manner: with annotations, with XML, with both combined, or by relying on convention and using the default implementation. Audit is a ubiquitous and rather trivial example for AOP. Interceptors can be used for a variety of other real-world purposes. Some ideas include:

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
19#
 楼主| 发表于 2008-10-30 09:38 | 只看该作者
*  Ensuring preconditions: Interceptors have access to the intercepted EJB -- not only to the methods, but to their parameters with annotations as well. It is relatively easy to evaluate the annotations and ensure the parameters' validity. For example, the annotation @NotNull already implies that the method should be invoked with a non-null parameter. With this approach, validation of the preconditions could be easily moved from the EJB into a reusable interceptor.
    * Ensuring service level agreements (SLAs):This case is similar to ensuring the preconditions. You could measure the performance of a method and escalate all too-slow invocations using, for example, a JMS topic wrapped in a session bean. This lightweight monitoring capability is especially important in service-oriented architecture (SOA) environments, where multiple clients must rely on the availability of a single, reusable service.
    * Enhancing DI capabilities: An interceptor can access the intercepted EJB instance directly, so it can access its fields and search for annotations. Additional values can be injected directly into a session bean's fields or methods. The Seam framework uses this approach. Integration with Google Guice can be approached in this way too.
    * Transforming and filtering exceptions: An interceptor invokes a method of the next participant in the chain. It wraps the invocation completely, so it can catch any encountered exceptions, swallow them, or rethrow clean versions. This is particular useful for dealing with legacy connectors with their own exceptions in the cause. (Not all exceptions, however, can be easily caught in an interceptor. Some exceptions, for example the javax.persistence.OptimistickLockException, might occur at the end of transaction. Because the interceptors are involved in the same transactions, it's impossible for them to catch such exceptions.)

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
20#
 楼主| 发表于 2008-10-30 09:39 | 只看该作者
In conclusion

EJB 3 -- especially EJB 3.1, with its support for no-interface views, WAR deployment, and singletons -- is even interesting for small and midrange applications. It is so streamlined that it's hard to slim it down any further. I don't know of any other framework that can implement simple CRUD functionality with less overhead than what you see in Listing 19.
Listing 19. CRUD with EJB 3.1 and without a business interface

@Stateless
public class BookMmgr{

    @PersistenceContext
    private EntityManager em;

    public void create(Book t) {
        this.em.persist(t);
    }

    public Book find(String id){
       return this.em.find(Book.class, id);
    }

    public void delete(Book t) {
       t = this.em.merge(t);
       this.em.remove(t);
    }

    public Book update(Book t) {
        return this.em.merge(t);
    }
}

Note that this example requires no XML. Only the EntityManager needs a few lines of configuration in the persistence.xml file.

New design patterns emerge from the synergy that comes from using EJB 3 with JPA entities. Even better, EJB 3 lets you do without most of the J2EE "best practices" that made that framework so complex to use.

See the Resources section to learn more about EJB technology then and now.

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表