| EJB3.0中的依赖注入,截获器及其在WebLogic Server 10中的扩展 |
|
| Weblogic | |||||||||||||
| 作者是 Administrator | |||||||||||||
| 2007-11-29 06:20:54 | |||||||||||||
1 前言与EJB2.1相比,EJB3.0规范引入了两个重要概念:依赖注入(DI:Dependency Injection)和截获器(Interceptor),本文首先介绍了这两个概念并给出相关示例,然后分析了EJB3.0规范在这两方面的不足之处,最终深入探讨了WebLogic Server 10对它们的支持和扩展。 2 依赖注入2.1 基本概念 依赖注入是从开源社区的一些著名轻量级容器(如Spring、Pico container)中所发展出来的概念,其主要思想就是由容器而不是对象本身来负责处理对象之间的依赖关系。与传统的服务定位器相比,依赖注入具有易测试、弱侵入性等优点,这也就是为什么在最新的Java EE 5规范中引入它的原因。 对于EJB3.0来说,依赖注入就是由容器负责查找被依赖的对象并注入到依赖bean中,而bean本身不再需要进行JNDI或者context查询。此外,依赖注入发生在任何业务方法被调用之前,而且支持setter方法注入和域注入两种方式。 通过与标注结合使用,在bean类中声明依赖注入是非常简单的 (当然,也可以在部署描述符文件中声明依赖注入):
2.2 示例
@Stateless
public class ServiceBean implements Service {
private javax.sql.DataSource myDS;
@Resource(mappedName=“LocalDataSource")
public void setMyDS(javax.sql.DataSource ds) {this.myDS = ds;}
@EJB(beanName=“AccountBean")
private Account account;
}
在无状态会话bean ServiceBean中,声明了两个依赖:一个是数据源,一个是业务接口。在运行期间,EJB3.0容器一旦创建了ServiceBean的实例,就会分别通过方法注入和域注入将数据源对象和业务对象注入到ServiceBean中。 3 截获器3.1 基本概念 作为EJB3.0中提出的新概念,截获器是可以对bean的业务方法和生命周期事件进行拦截的组件。截获器需要由@Interceptors 或 发布描述符文件中相关的标签指定。截获器可以带有状态而且可以进行依赖注入,其生命周期与其所绑定的EJB bean实例的生命周期一致。 定义在截获器中用于拦截目的的方法被称为截获器方法,其中,针对业务方法的截获器方法通过@AroundInvoke标注或发布描述符文件中相关的标签指定;针对生命周期回调的截获器方法通过@PostConstruct, @PreDestroy等标注或发布描述符文件中对应的标签指定。 截获器分为四类:
3.2 截获器链的调用顺序 因为可以为EJB定义多个截获器,所以存在截获器链的调用顺序问题,缺省情况下,以下原则被遵循(请参考下图): 图1:截获器链的缺省调用顺序
此外,EJB3.0规范还提供了更灵活的选项,详细信息请参考EJB3.0规范中“截获器”一节:
图2:由interceptor-order指定的一种可能的截获器链调用顺序 3.3 示例
@Stateless(name="Trader")
@Interceptors(ClassInterceptor.class)
public class TraderBean implements Trader {
@Interceptors(MethodInterceptor.class)
public String sell(String stockSymbol) {
…
}
@AroundInvoke
public Object selfInterceptor(InvocationContext) throws Exception {
…
}
}
在无状态会话bean TraderBean中,声明了两个截获器:一个类级截获器,一个方法级截获器,此外,通过使用@AroundInvoke标注,TraderBean的方法selfInterceptor被声明为截获器方法,所以TraderBean就是bean级截获器。 4 EJB3.0规范在依赖注入和截获器方面的不足从依赖注入方面来说,EJB3.0目前支持的注入类型是非常有限的,诸如List、Map之类的集合类型都不能被注入。 另一方面,EJB3.0的截获器可被看作是一种AOP模型,截获器类相当于方面(Aspect),而截获器方法相当于通知(Advice),但这种AOP是非常简单的:
5 WebLogic Server 10 EJB3.0容器简介5.1 Pitchfork 简介 Pitchfork是由Interface21与BEA合作开发的一个具有Apache License的开源项目,作为Spring的“增值”项目,开发Pitchfork有两个目的:
5.2 WebLogic Server 10 EJB3.0容器的架构
图3:WebLogic Server 10 EJB3.0容器的架构 WebLogic Server 10完全支持Java EE 5和EJB3.0,其EJB3.0 容器是基于Pitchfork来实现依赖注入与截获器的,而Pitchfork又利用了Spring的依赖注入和AOP。此时,WebLogic Server 10的用户有两种选择:
6 Spring扩展模型6.1 使用Spring扩展模型的主要开发步骤
需要注意的是,在Spring配置文件中定义的bean,如果它也是一个EJB bean,则该Spring bean的class属性会被忽略以避免潜在的冲突。 6.2 示例 示例一:利用Spring的依赖注入。本例将演示两点,(1) 注入一个集合类型,(2) 注入一个Spring POJO对象 (1) 开发一个bean类
@Stateless(name="AccountManagementBean")
@Remote({examples.AccountManagement.class})
public class AccountManagementBean
{
private List accountList;
private BusinessObject businessObject;
public boolean doBusiness(String account) {
if (accountList.contains(account)) {
businessObject.doBusiness();
return true;
}
return false;
}
public BusinessObject getBusinessObject() {
return businessObject;
}
public void setBusinessObject(BusinessObject businessObject) {
this.businessObject = businessObject;
}
public List getAccountList() {
return accountList;
}
public void setAccountList(List accountList) {
this.accountList = accountList;
}
}
(2) 一个POJO
public class BusinessObjectImpl implements BusinessObject
{
private String result;
public void doBusiness() {
System.out.println("I am doing business, the result is: " + result);
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
}
(3) Spring-ejb-jar.xml … <beans> <bean name="BusinessObject" class="examples.BusinessObjectImpl"> <property name="result" value="success" /> </bean> <bean id="AccountManagementBean"> <property name="businessObject" ref="BusinessObject" /> <property name="accountList"> <list> <value>Safin</value> <value>Amy</value> <value>Albert</value> <value>Yang</value> </list> </property> </bean> </beans> 示例二:利用Spring 的AOP。本例演示了混合使用JEE interceptor、基于代理的Spring AOP以及AspectJ的Aspect (1) 开发一个bean类
@Stateless(name="AccountManagementBean")
@Remote({examples.AccountManagement.class})
public class AccountManagementBean
{
public AccountManagementBean() {}
@Interceptors({examples.JEEInterceptor.class})
public boolean doBusiness(String account) {
System.out.println("I am doing business " + account);
return true;
}
}
(2) 开发一个JEE interceptor
public class JEEInterceptor {
@AroundInvoke
private Object intercept(InvocationContext inv) throws Exception{
System.out.println("I am in JEEInterceptor.intercept()");
return inv.proceed();
}
}
(3) 开发一个Advice
public class SimpleAdvice implements MethodInterceptor{
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("I am in Spring AOP interceptor");
return invocation.proceed();
}
}
(4) 开发一个Pointcut
public class SimpleStaticPointcut extends StaticMethodMatcherPointcut {
public boolean matches(Method method, Class cls) {
return "doBusiness".equals(method.getName());
}
public ClassFilter getClassFilter() {
return new ClassFilter() {
public boolean matches(Class cls) {
return AccountManagementBean.class.isAssignableFrom(cls);
}
};
}
}
(5) 开发一个AspectJ Aspect
@Aspect
public class Aspects {
@Around("execution(* examples.AccountManagementBean.doBusiness(..))")
public Object around(ProceedingJoinPoint pjp) {
System.out.println(“I am in AspectJ aspect);
Object retVal = null;
try {
retVal = pjp.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
return retVal;
}
}
(5) Spring-ejb-jar.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"> <bean id="AccountManagementBean" /> <bean id="myAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"> <property name="advice"> <bean class=”examples.SimpleAdvice” /> </property> <property name="pointcut"> <bean class="examples.SimpleStaticPointcut" /> </property> </bean> <bean id="MyAspect" class="examples.Aspects" /> </beans> 6.3 优点 提供Spring扩展模型具有如下好处:
7 Spring AOP在WebLogic Server 10 Spring扩展模型中的使用限制及说明7.1 代理生成方式 Spring AOP采用的是一种基于代理的框架,目前有两种生成代理的方式:JDK动态代理和CGLIB。在WebLogic Server 10的Spring扩展模型中,目前不支持CGLIB方式,这主要是因为生成的EJB类都是final的 7.2 代理创建 在Spring中,代理或者是通过诸如ProxyFactoryBean之类的工厂bean明确创建,或者是通过“自动代理”创建器隐含创建。 在WebLogic Server 10中,Pitchfork已经隐含提供了类似的“自动代理”机制,所以原有的Spring代理创建方式是无效的,换句话说,用户只需要在Spring配置文件中定义目标bean以及对应的Spring Advisor和AspectJ Aspect, 不需要再定义ProxyFactoryBean和“自动代理”创建器,Pitchfork会自动为我们创建AOP代理 7.3 截获的顺序问题 在Spring扩展模型中,可以混合使用JEE截获器、Spring Advisor以及AspectJ Aspect,此时的调用顺序为JEE截获器、Spring Advisor以及AspectJ Aspect。 7.4 bean的实例化模式 缺省方式下,Spring bean是Singleton的,即Spring容器总是返回同一个bean实例,在Spring扩展模型中,这意味着同一个Spring Advisor或AspectJ Aspect实例将被应用到不同的EJB bean实例上,如果Advisor或Aspect实例是有状态的,这可能会产生问题,为此我们推荐如下的使用方式:
8 结束语依赖注入和截获器的引入,使得EJB3.0克服了很多EJB2.1的缺点,但与开源社区中流行的轻量级容器相比,EJB3.0无论是在依赖注入的范围还是在AOP的易用性方面都还存在一定的不足。而最近BEA所推出的WebLogic Server 10不但完全支持EJB3.0,而且对其进行了有效扩展,这使得一方面可以充分利用在开源社区中出于领导地位的Spring在依赖注入和AOP方面的强大能力,另一方面又紧密依托WebLogic Server 10在事务、安全、集群方面领先的技术,从而为EJB3.0用户开发出易维护、可扩展、高效率的企业应用程序打下坚实的基础。 |
|||||||||||||
| 最近更新 ( 2007-11-29 06:20:54 ) | |||||||||||||




