第
2
章
EJB
知识与运行环境设置(
2
)
(上接第
2
章的第
1
部分)
16.
改变
JNDI
名称
1)
对于
JBoss
应用服务器,可以使用
JBoss
提供的
@LocalBinding
和
@RemoteBinding
注释来指定会话
Bean
的
JNDI
名称。例如:
@RemoteBinding(jndiBinding=”foshanShop/RemoteOperation”)
@LocalBinding(jndiBinding=”foshanShop/LocalOperation”)
2)
对于
WebLogic
、
Sun
Application Server
、
Glassfish
等应用服务器,可以使用
@Stateless
的
mappedName()
属性设置
Bean
的全局
JNDI
名称。例如:
@Stateless(mappedName=”OperationBeanRemote”)
3)
为了避免
JNDI
名称与厂商相关而造成的移植问题,建议使用
ejb-jar.xml
部署描述文件进行定义。该文件必须置于
jar
的
META-INF
目录下。
17.
会话
Bean
的生命周期事件
1)
@PostConstruct
:
适用于有状态和无状态会话
Bean
。当
Bean
实例化完成后,标注了这个注释的回调方法会被立即调用,且仅此一次调用。每个
Bean
类只能定义一个
@PostConstruct
方法。
2)
@PreDestroy
适用于有状态和无状态会话
Bean
。当容器销毁一个无用的或者超时的
Bean
实例时,标注了这个注释的回调方法会被调用,且仅此一次调用。每个
Bean
类只能定义一个
@ PreDestroy
方法。
3)
@PrePassivated
适用于有状态会话
Bean
。当
Bean
实例被钝化之前,具有该注释的回调方法会被调用。如果钝化期间,客户端仍然长期没有对
Bean
实例进行操作,则容器会从硬盘上删除它。此后,任何针对这个
Bean
实例方法的调用,都会导致异常。
4)
@PostActivated
适用于有状态会话
Bean
。当
Bean
实例从钝化状态被激活时,容器会重新实例化一个新的
Bean
实例,并从硬盘恢复钝化之前的状态。完成激活之后,具有该注释的回调方法会被调用。
5)
@Init
用于指定有状态会话
Bean
的初始化方法。其与
@PostConstruct
的区别在于,有状态会话
Bean
中可以存在多个
@Init
标注的方法。
@PostConstruct
在
@Init
之后被调用。
6)
@Remove
当客户端调用了标注为
@Remove
的方法时,容器会在方法执行结束后,删除
Bean
实例。
7)
对于上面的注释方法,必须是
void
,不带参数的,不抛检查异常的方法。
8)
@PostActivate
与
@PostConstruct
,
@PrePassivate
与
@PreDestroy
之间实质上并无很大差别。
l
@PostActivate
和
@PostConstruct
通常都应该用于初始化或恢复无法序列化的资源,比如数据库连接;
l
@PrePassivate
和
@PreDestroy
通常都应该用于关闭无法序列化的资源。因为进入钝化状态后,当
Bean
实例超时,容器在清除
Bean
实例之前,是不会调用
@PreDestroy
方法关闭尚处于打开状态的资源的,比如数据库连接。
18.
拦截器用于封装应用的公用行为,可以拦截会话
Bean
和消息驱动
Bean
的方法调用或生命周期事件。
19.
开发拦截器
1)
@AroundInvoke
注释
l
该注释用于指定用作拦截器的方法。拦截器方法与被拦截的业务方法在同一个
Java
调用堆栈、同一个事务和安全上下文中。
l
用
@AroundInvoke
标识的方法必须遵守以下格式:
public Object methodName(javax.interceptor.InvocationContext
ctx) throws Exception
2)
InvocationContext
此上下文接口封装了关于客户端所调用业务方法的一些信息:
l
getTarget()
:返回
Object
,指向被调用的
Bean
实例。
l
getMethod()
:返回
Method
,指向被拦截的业务方法。
l
getParameters()
:返回
Object[]
数组,指向被拦截业务方法的参数。
l
setParameters()
:返回
void
,设置被拦截业务方法的参数。
l
getContextData()
:返回
Map<String,
Object>
,在整个方法调用期间都可以访问。同一方法调用内的不同拦截器之间可以利用这个
Map
来传递上下文相关的数据。
3)
proceed
方法,返回
Object
l
InvocationContext
的
proceed()
方法内部会继续调用后面拦截器的
@AroundInvoke
方法,直到所有的拦截方法全都被调用以后,才会执行被拦截的业务方法。(个人感觉,有点像
FilterChain
的
doFilter
方法)
l
proceed()
方法必须在拦截器代码中调用,否则被拦截的业务方法最终就无法被调用到。
l
如果想在被拦截的业务方法执行结束后在执行一些自定义的代码,可以在
proceed
执行后、拦截器方法返回之前加入自己的代码。
4)
因为拦截器方法和被拦截的业务方法处于相同的
java
调用堆栈,因此可以通过抛出异常,来终止方法的执行。
5)
除了在外部类中定义拦截器方法,还可以在会话
Bean
内部将
Bean
的一个或多个方法定义为拦截器。仍然是使用
@AroundInvoke
和上述的那种方法格式。执行流程也是一样的。
20.
使用拦截器
1)
使用外部类类型的拦截器,可以用
@Interceptors
注释。这个注释接受拦截器类的
.class
属性值,多个
.class
通过逗号分隔。可以标识在类级,表明拦截类中的所有方法;也可以标识在方法级,表明只对某一方法进行拦截。
2)
如果是在
Bean
类内部,将方法标识为
@AroundInvoke
,则该方法将会拦截
Bean
中的所有方法。
3)
默认拦截器
l
通过
ejb-jar.xml
可以定义默认拦截器,
ejb-jar.xml
文件需要置于
jar
文件的
META-INF
目录:
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<
ejb-jar
version
=
"3.0"
xmlns
=
"http://java.sun.com/xml/ns/javaee"
xmlns:xml
=
"http://www.w3.org/XML/1998/namespace"
xmlns:xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation
=
"http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd "
>
<
assembly-descriptor
>
<
interceptor-binding
>
<
ejb-name
>
*
</
ejb-name
>
<
interceptor-class
>
cn.gengv.ejb3ex.interceptor.LogInterceptor
</
interceptor-class
>
</
interceptor-binding
>
</
assembly-descriptor
>
</
ejb-jar
>
l
<ejb-name>*</ejb-name>
指明拦截所有的
EJB
的所有方法。如果只想拦截某一个
EJB
,则可以用这个
EJB
的名称替换通配符“
*
”。其效果和在
Bean
类上标识
@Interceptor
的效果
是一样的。
l
<intercepter-class>
用来指定拦截器类。
4)
禁用拦截器
l
可以使用
@ExcludeDefaultInterceptors
注释来禁用默认拦截器,该注释可以标识在
Bean
类级或业务方法级。
l
虽然可以通过
@ExcludeDefaultInterceptors
注释来禁用默认拦截器,
Bean
类仍然可以通过
@Interceptors
注释来使用自己所需要的拦截器。
5)
拦截生命周期事件
l
与定义
@AroundInvoke
方法非常类似,只是使用回调注释,替代
@AroundInvoke
。例如:
@PostConstruct public void
methodName(InvocationContext ctx)
l
因为生命周期事件的回调方法没有返回值,因此拦截方法也必须是
void
。而且拦截方法不能有
throws
子句。
l
其他特性和
@AroundInvoke
拦截方法相同。
6)
根据自己的测试,默认拦截器会在
Bean
自己指定的拦截器之前调用