如何为EAR中的所有WAR应用配置单一类加载器(WebSphere Liberty)
我正尝试将遗留应用从WAS 9.0.5迁移至WebSphere Liberty,应用结构如下:
EarApplication.ear |--> META-INF |-->application.xml |--> WebApplication1.war |---> META-INF |--> MANIFEST |----->WEB-INF |--> classes |--> lib |--> WebApplication1Client.jar |--> WebApplication2Client.jar |--> Other libs |--> WebApplication2.war |---> META-INF |--> MANIFEST |----->WEB-INF |--> classes |--> lib |--> WebApplication2Client.jar |--> Other libs
WebApplication1Client.jar包含的JAX-RS定义类:
@Path("a") public interface A { @GET @Path("a-method") AB getA(); class AB implements Serializable { ... } }
WebApplication1.war包含的EJB实现类(注:原文@Steteless为笔误,修正为@Stateless):
@Stateless @Local(A.class) public class AImpl implements A { @EJB private B b; @Override public AB getA(){ BB bb = b.getB(); return getABFromBB(bb); } private AB getABFromBB(BB bb){ ... } }
WebApplication2Client.jar包含的JAX-RS定义类:
@Path("b") public interface B { @GET @Path("b-method") BB getB(); class BB implements Serializable { ... } }
WebApplication2.war包含的EJB实现类(注:原文@Steteless为笔误,修正为@Stateless):
@Stateless @Local(B.class) public class BImpl implements B { @Override public BB getB(){ return new BB(); } }
由于WebApplication1.war和WebApplication2.war由不同类加载器加载,出现如下异常:
CWOWB1000E: 发生CDI错误:CWNEN0074E: 为java:comp/env/AImpl/b引用获取的EJSLocal_B_64388ed6类型的对象实例与AImpl成员B的类型不兼容。
在WAS 9.0.5中,可通过在应用级别勾选“Single class loader for application”(应用单类加载器)选项解决该问题,但WebSphere Liberty文档未提及相关配置选项,当前server.xml配置如下:
<server> <features> <feature>javaee-7.0</feature> </features> <applicationManager autoExpand="true"/> <enterpriseApplication location="EarApplication.ear"/> </server>
请问WebSphere Liberty中是否有类似WAS的配置选项来解决该问题?
解决方案
WebSphere Liberty中提供了对应的配置属性来实现和WAS 9.0.5“应用单类加载器”相同的效果:
在<enterpriseApplication>元素中添加classLoadingMode="SINGLE"属性,修改后的server.xml如下:
<server> <features> <feature>javaee-7.0</feature> </features> <applicationManager autoExpand="true"/> <enterpriseApplication location="EarApplication.ear" classLoadingMode="SINGLE"/> </server>
该配置会让整个EAR应用使用单一类加载器,所有模块(war、jar)共享同一个类加载上下文,这样WebApplication1和WebApplication2加载的B接口类会是同一个实例,从而避免类型不兼容的异常。
另外,更推荐的优化方案是:将共享的WebApplication1Client.jar和WebApplication2Client.jar移动到EAR根目录的lib文件夹下(若不存在则创建),这样这些共享类会被EAR的类加载器加载,所有子模块(war)都可以共享这些类。这种方式既解决了类加载器冲突问题,又比全局单类加载器更符合Java EE的模块化规范,减少不必要的类共享。
内容的提问来源于stack exchange,提问作者Kapik001

