您的位置:首页 > 编程语言 > Java开发

【JavaEE】经典JAVA EE企业应用实战-读书笔记11

2017-02-14 15:47 316 查看
Bean管理事务,主要就是通过UserTransaction来控制事务开始、结束。
首先需要获得UserTransaction,有三种方式
1)使用@Resource执行依赖注入
2)通过JNDI查找来获取,代码如下
UserTransaction tx=(UserTransaction)ctx.lookup(“UserTransaction”);
3)使用EJBContext的getUserTransaction方法,代码如下
UserTransaction tx=ctx.getUserTransaction();
其中第一中比较简单,接着在代码使用
tx.begin();tx.commit();tx.rollback();
 
下面是UserTransaction所包含方法的简单解释
begin:用于开始新的事务,创建一个新的事务,并将他关联到当前执行线程中。
commit:用于提交事务,将会结束当前线程关联的事务
getStatus:用于获取当前线程关联的事务状态
rollback:用于回滚事务,同样结束当前线程关联的事务
setRollbackOnly:只能在CMT事务管理器中使用,用于通知容器回滚当前事务。
setTransactionTimeout(int secondes):用于修改当前线程所关联事务的超时时长
上面的方法中getStatus是EJBContext中getRollbackOnly方法的复杂版,getRollbackOnly只能返回一个boolean值,而getStatus方法则返回代表当前事务状态的值,包括
javax.transaction.Status.STATUS_ACTIVE:当前线程处于活动阶段
javax.transaction.Status.STATUS_COMMITTED:当前线程已经被提交
javax.tr
4000
ansaction.Status.STATUS_COMMITTING:当前线程正处于提交过程中
javax.transaction.Status.STATUS_MARKED_ROLLBACK:当前线程已被标记为回滚。可能是由于当前线程调用了UserTransaction的setRollback(true)方法。
javax.transaction.Status.STATUS_NO_TRANSACTION:当前线程没有事务支持
javax.transaction.Status.STATUS_PREPARED:当前事务正准备提交,正在等待从属资源的响应
javax.transaction.Status.STATUS_PREPARING:当前事务处于预备阶段,所有从属资源都已经同意提交
这两个状态值与两段式提交有关,两段式提交协议方式在正式提交事务之前,需要先尝试提交该事务的多个从属源,只有当从属源尝试提交都返回成功时,JTA全局事务才会正式提交。在第一阶段中尝试提交了多个从属资源,当这些从属资源的结果尚未返回时,事务处于STATUS_PREPARING状态;当这些从属资源都返回了提交成功时,这意味着JTA全局事务可以真正提交了,那么事务处于STATUS_PREPARED状态。
javax.transaction.Status.STATUS_ROLLEDBACK:当前事务已经被回滚了
javax.transaction.Status.STATUS_ROLLING_BACK:当前事务处于回滚过程中
javax.transaction.Status.STATUS_UNKNOWN:当前事务处于未知状态
EJB容器建议使用CMT,因此CMT也是默认配置。因为BMT需要开发者硬编码来实现,导致业务逻辑和事务逻辑混杂,也导致了Session
Bean的事务逻辑难以切换成其他管理方式。BMT还有一个严重问题,当客户端调用BMT方法时,总会暂停当前已有事务,制约了组件的重用。
 
EJB3提供了拦截器支持,但是只提供了一个@AroundInvoke。用于修饰EJB3中的拦截器方法。
public class MyInterceptor {
@AroundInvoke
public Object log(InvocationContext ctx) throws Exception {
System.out.println("interceptor start");
// 让目标方法执行
Object rvt = ctx.proceed();
if (rvt != null) {
rvt = "interceptor change return value " + rvt;
}
System.out.println("interceptor end");
return rvt;
}
}

需要注意的是@AroundInvoke修饰的方法必须满足如下格式
public Object xxx(InvocationContext ctx)throws Exception
InvocationContext 对象中包含如下方法
1)Map<String,Object> getContextData():Map对象里封装了本次调用或生命周期回调相关的上下文信息
2)Method getMethod():获取被拦截的方法
3)Object[] getParameters():获取被拦截的业务方法的实际参数
4)Object getTarget():获取被拦截的Session Bean实例
5)Object proceed():调用InvocationContext的该方法是就是回调拦截方法、执行被拦截方法
6)void setParameters():修改被拦截的业务方法的实际参数
 
在需要被拦截的Bean实现类使用@Interceptors(MyInterceptor.class)来修饰类或业务方法。
如果修饰类的话,对类中所有业务方法都起作用,但是可以使用@ExcludeClassInterceptors来排除某个方法不使用拦截器。
 
EJB注入只要靠位于javax.ejb包下@EJB、@EJBs两个注解来提供。@EJB即可用于修饰Bean实现类的成员变量,也可用于修饰Bean类的setter方法
使用@EJB是可指定如下属性
1)beanInterface:指定被注入EJB所实现的接口。通常用于区分所引用的Bean是远程调用Bean还是本地Bean。
2)name:指定被注入Bean在JNDI
ENC中的注册项名称,该名称在不同应用服务器中可能存在差异。
3)beanName:指定被注入EJB的名称。其值与被注入Bean中@Stateless.name、@Stateful.name或ejb-jar.xml中的<ejb-name>元素所指定的值相等。
4)mappedName:指定被注入EJB的JNDI名,但由于全局JNDI名与应用服务器厂商有关系,因此设置改属性可能降低应用的可移植性。
ENC的全称是Enterprise Naming Context,是应用服务器的一个内部注册表。
前面说本地调用EJB在WebLogic服务器中不会被暴露出来,只能被位于同一个应用中的其他组件调用,此处将会介绍通过EJB注入将本地调用的EJB注入远程调用的EJB中,从而间接地让本地EJB也可以对外提供服务。
@Local
public interface Hello{
public String hello(String name);
}

@Stateless(name=”Hello”)
public class HelloBean implements Hello{
public String hello(String name){
return “hello” + name + new java.util.Date();
}
}

@Remote
public interface CallHello{
String callHello(String name);
}

@Stateless(mappedName=”CallHello”)
public class CallHelloBean implements CallHello{
@EJB(beanName=”Hello”)
private Hello hello;
public String callHello(String name){
final String prefix=”调用Hello EJB成功,返回”;
String result=hello.hello(“kingdz”);
System.out.println(prefix+result);
return prefix+result;
}
}

通常使用@Resource来实现资源的注入,用法和@EJB类似。
@Resource可使用如下几个属性
1)String mappedName:指定该资源的JNDI引用名称
2)String name:该属性指定外部资源的JNDI ENC名称,该名称在不同的应用服务器中可能会有变化
3)boolean shareable:该属性指定该资源是否可以共享
4)Class type:该属性指定该资源对应的Java类名
例如:
@Resource(mappedName=”javaee”)
private DataSource ds=null;
@Resource
private SessionContext sessCtx;
 
配置EJB引用
除了依赖注入,还可以使用EJB2的形式,在ejb-jar.xml部署描述文件中进行配置。
通过在<session>元素中添加如下两个元素
<ejb-ref>:为一个Remote EJB配置EJB引用
<ejb-local-ref>:为一个Local EJB配置EJB引用
上面两个元素都用于为一个Session Bean配置EJB引用,都可以添加如下子元素:
<ejb-ref-name>:用于为EJB配置一个名称
<ejb-ref-type>:指定所引用EJB的类型,在EJB3规范中该属性的值通常是Session
<local>或<remote>:用于指定EJB业务接口的全限定类名
例如
<session>
<!--指定为哪个EJB配置EJB引用-->
<ejb-name>EJBRef</ejb-name>
<ejb-local-ref>
<!--指定EJB引用的名称-->
<ejb-ref-name>ejb3/Hello</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<!--指定所引用EJB所实现的业务接口-->
<local>com.kingdz.service.Hello</local>
</ejb-local-ref>
</session>
此处配置的EJB引用名可能并不一定就是完整的JNDI绑定名。
 
EJB3的定时器服务由TimerService对象代表,调用createTimer方法,有如下几个参数
1)Date initialExpiration:指定定时器将于指定的initialExpiration时刻触发
2)long intervalDuration:指定定时器的触发时间间隔为intervalDuration毫秒
3)Serializable info:指定一个描述性信息
 
调用createTimer方法之后,会为该EJB创建一个定时器对象,就会控制EJB内被@Timeout修饰的方法在指定时间执行,@Timeout修饰的方法必须满足如下签名
public void xxx(Timer timer);
被@Timeout修饰的方法不应该由客户端来调用,应该由定时器负责调用。
Timer对象提供了如下方法来访问定时器
1)void cancel:取消定时器
2)TimerHandle getHandle:获取定时器的引用
3)Serializable getInfo:获取定时器的描述性信息。就是调用createTimer方法通过info参数传入的信息
4)Date getNextTimeout:获取该定时器下一次触发的时刻
5)long getTimeRemaining:获取定时器还需多少毫秒将会触发下一次任务调度
@Remote
public interface TimerEJB {
void setTime(Date init, long interval);
void check(Timer timer);
}
@Stateless(mappedName = "TimerEJB")
public class TimerEJBBean implements TimerEJB {
@Resource
TimerService timerService;
@Override
@Timeout
public void check(Timer timer) {
System.out.println(timer.getInfo());
System.out.println("mock system check");
}
@Override
public void setTime(Date init, long interval) {
timerService.createTimer(init, interval, "new timer");
}
}
Timer对象提供了一个getHandle方法获取该定时器对应的TimerHandler对象。而TimerHandler是可序列化的,但该对象不应该通过网络传输,也就是说他不能传给客户端,即远程客户端不能访问EJB的TimerHandler对象。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: