EJB3中SessionBean使用Local及Remote接口的注意事项
来源:互联网 发布:杠杆率 知乎 编辑:程序博客网 时间:2024/05/17 18:28
使用EJB3开发已经快一年了,觉得是时候总结一下,顺道分享一下一些个人在开发过程中的一些心得,希望能对各位刚开始开发的朋友有所帮助。
废话不多说,直接正题。
这次主要是讲述为何SessionBean中的Local接口在某些情况下不能使用自定义类型的情况以及可能的解决方法。
众所周知,一个标准的EJB3中大大简化了SessionBean的业务接口(无论是数量还是编码量上),这样SessionBean只需要实现对应接口并讲接口分发到对应客户端即可。
但是,实际情况并没有这么简单。
首先说下Local接口:
在网上,能找到的例子Local接口中的方法通常都是以下形式的:
void service();
void service(String);
String service(String);
String service(String) throws Exception;
可以发现一点,这里的类型除了Local接口本身是自定义类型之外都是Java自身提供的类型,这种类型有个特点,就是其类实例是被Java的系统类加载器加载的。至于为何要提及这一点,在后面会提及。
现在我们来写一个稍微复杂一点的业务方法
其中,CustomResult、CustomParam、CustomException均为自定义类型。
将写好的EJB组件打包成.jar包发布到服务器,发布顺利完成,这里我们来写个Servlet来调用这个SessionBean,将所需要的类(Local接口,及Local接口Import的类)复制至对应项目的classPath中,以下是调用SessionBean的代码片段:
说明:上述代码只给出部分主要的代码片段
客户端也写好了,将客户端打包成一个.war包也发布到与EJB相同的同一服务器中(例如同一个JBoss)。
此时EJB组件以及Web应用都运行在同一个JVM环境下,按照绝大部分的讲法,在同一个JVM中调用Local接口是可行的,但是现在执行一下,你将会收到一个类似这样的异常:IllegalArgumentException:“Wrong Target”,意思是目标不正确。
但如果将STSBServiceLocal中的execute方法的自定义类型换为基本类型则可行。
为何会出现这个异常,明明在同一个JVM中,拥有自定义类型的Local业务接口却不能正常调用?
其实原因在于大多数应用服务器(Application Server)都通过使用自定义类加载器的方式来实现服务器上的应用服务间的隔离以,以保证应用服务的相对独立性。如果EJB组件与web应用的服务包是互相分开发布的,这样EJB组件和Web应用将会被两个分别不同的类加载器加载,由于Java定义一个类是通过类加载器及类全称限定名称({ClassLoader, QualifiedName})来确定一个唯一的类的,所以分开发布的两个包中的自定义类型会认为是两个不同的类型,这样无异于在接口中声明的是 String execute(Boolean) 方法,但是调用的却是 Double execute(Float) 方法一样。
又为何使用Java自身的类型却不会出问题,原因就是Java自身的类在一开始就被加载,并且类加载器通常采用parent-first策略,所以Java自身的类型在同一个JVM中无论在哪里引用有且只有一个类实例,所以使用基本类型就不会出错。
针对这一点的解决方法有两个,第一个是讲EJB组件以及Web服务打包为一个EAR包发布,这样Web应用就可以正常调用EJB组件了。
但是这样的做法有一定的局限性,而且一旦某个EJB组件依赖的包与Web应用发生冲突,这时就只能将两个包分开发布。
在分开发布的时候由于客户端(Web应用)与EJB服务不再处于同一个类加载器中,这时可能就要通过修改Local接口,或者使用Remote接口来解决自定义类型不能使用的问题。
如果不能修改接口并且坚持要使用Local接口(因为Local接口的性能比Remote高),在JBoss下(因为我只熟悉JBoss的配置,其它服务器的请自行琢磨)有个方案,就是使用jboss-classloading.xml以及jboss-classloading-domain.xml(放在META-INF或WEB-INF下),来控制类加载策略(具体配置见文章末端)。
最后提及一下Remote接口,通过这个接口调用的Bean所涉及的自定义类型均需要实现Seriallizable接口并且创建一个为一个的serialVersionUID。
由于Remote接口的调用是基于RMI协议的,所以所有自定义的类将会被序列化并传输到客户端,而通过序列化后的类不再是通过{ClassLoader, QualifiedName}这种形式类判断两个类是否同一个类,而是通过serialVersionUID来判断,如果serialVersionUID不同则会抛出一个DeserializeException(好像是这个名字),意思是无法反序列化这个类。
JBoss类加载具体的配置:
jboss-classloading-domain.xml
此文件的作用是定义一个类加载的域,同一域中的类可以在一定程度上共享。
jboss-classloading.xml
此文件的作用是为应用配置一个独立的类加载器,domain属性将此类加载器加入刚才定义的YourDomain域中。
- EJB3中SessionBean使用Local及Remote接口的注意事项
- 菜鸟学EJB(二)——在同一个SessionBean中使用@Remote和@Local
- Spring访问EJB3.0的SessionBean方法
- .NET 中接口使用时的注意事项
- ejb中sessionbean的见解
- 在jboss 4.2.3GA中开发EJB3,使用local时遭遇接口类型转换出错的奇怪问题
- 使用接口的注意事项
- 接口使用的注意事项
- jboss中远程(remote)和本地(local)的区别
- JBoss5中Local与Remote不能同时存在的问题
- 关于github中local与remote不能同步的问题
- EJB Local与Remote接口区别
- local和remote的区别
- local和remote的区别
- remote和local 的区别
- 接口的运用及注意事项
- Java中数组的使用及注意事项
- PHP中$_FILES的使用及注意事项
- dbms_metadata role
- singleton_单实例
- Flex标签语法的使用
- QWidget的使用
- jstl与jsp的版本问题:root cause java.lang.NoClassDefFoundError: javax/el/ELException
- EJB3中SessionBean使用Local及Remote接口的注意事项
- MOSS 2010 localized resources
- 在Arch Linux下安装Chrome的DEB包
- android如何访问webservices (wsdl 或 asmx)
- java定时任务处理
- 新手电子商务SEM专员操作指南
- dentry 与inode的概念
- 适配器模式(Adapter)
- 软件工程 敏捷的酒后问答