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域中。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 在基本农田建有机肥厂怎么办 有机肥厂的环评怎么办 织玻璃纤维网布环评怎么办 吃了受潮的奶粉怎么办 喝了受潮的奶粉怎么办 刚买的奶粉受潮怎么办 羊不小心吃了化肥怎么办 阿胶粉结成块了怎么办 半桶奶粉受潮了怎么办 眉粉受潮了结块怎么办 刚买的奶粉结块怎么办 袋装白糖成坨了怎么办 一袋子白糖硬了怎么办 粉饼上有一层油怎么办 葡萄后期氮肥施用过多怎么办 没洗的菜吃了怎么办 闻了汽油味头晕怎么办 碰到绿萝的汁液怎么办 吃了带农药水果怎么办 开槽模切一体机模切时开槽怎么办 柔版印刷走纸歪斜怎么办 美团外卖一天8单怎么办 单位显示器丢了怎么办员工赔 纸板板门起泡了怎么办 卖家要我开出质量问题证明怎么办 闲鱼买到的商品不符合描述怎么办 寄出去的东西碎了怎么办 闲鱼快递损坏了怎么办 寄快递东西坏了怎么办 快递邮寄东西坏了怎么办 快递被别人拆了怎么办 淘宝买的东西包装破损怎么办 寄血液被退回来怎么办 快递被安检扣了怎么办 淘宝原单退回运费怎么办 运输过程中包裹破损怎么办 天猫没收到货签收怎么办 收到的快递坏了怎么办 自寄的快递少了怎么办 邮的东西弄坏了怎么办 物流签收后发现货物损坏怎么办