问题:aar 无法提供classpath的环境
尽管aar环境非常象WEB-INF/class, 但aar不提供classpath的环境
服务代码:
package com.machome.test;import com.machome.model.Student2;public class TestHibernate { public static void main(String[] args) { System.out.println(findById(3)); } public static String findById(int id) { Configuration cfg = new Configuration(); SessionFactory sf =null; Session session = null; Transaction tran = null; try { sf =cfg.configure().buildSessionFactory(); session = sf.openSession(); tran = session.beginTransaction(); Student2 stu = (Student2)session.get(Student2.class, id); return stu.getName(); } catch (HibernateException e) { e.printStackTrace(); return null; }finally{ tran.commit(); session.close(); sf.close(); } } } 我们执行的ant target如下: 生成aar文件,形成类似WEB-INF/classes的目录结构
<target name="generate.service" depends="compile.service"> <!--copy services.xml --> <copy toDir="${service.target}/classes" fail> <fileset dir="${basedir}/resources"> <include name="**Test.class" dir="${service.target}/classes"/> </jar> </target>形成的TestHibernate.aar包结构如下:TestHibernate.aar |----com |--machome |--model |-- Student2.class |-- Student2.hbm.xml |--test |-- TestHibernate.class |---META-INF |--MANIFEST.MF |--services.xml |---hibernate.cfg.xml 而实际部署到axis2项目的后果:
hibernate.cfg.xml放在aar内,axis2项目报错找不到service 类 调用其他实体类(Student2),但
实体类放在aar中没用,axis2项目报错找不到hibernate如果采用hbm mapping文件(Student2.hbm.xml),则
hbm mapping放在aar中没用,axis2项目报错找不到
解决法1: 按普通项目部署,将需要的配置文件,类文件,库部署到axis2项目的buildpath(比如:WEB-INF/classes和lib
--src---- |--com.machome.model |--Student2.java |--Student2.hbm.xml |--hibernate.cfg.xml --webroot-- |--WEB-INF |-classes |--com.machome.model |-- Student2.class |-- Student2.hbm.xml |--hibernate.cfg.xml |-lib |-- jar file |-conf |-modules |-services |-TestHibernate.aar 这是最常见的解决办法, 目前google和百度上能搜索到的都是这个解决办法.
其实这个解决办法也是最合理的,多数人甚至并没有通过网上搜索解决,完全自己就能想出来,毕竟支持文件和库找不到,肯定是build path 和classpath出问题,而众所周知的build path其实就两种:1.classpath环境变量指定 2.web container 的WEB-INF/classes和lib
问题的原因和原理:
AXIS2 没对每个service 设置专门的classloader, 而是实现一个统一的classloader, 由这个classloader管理所有的service
这个统一的classloader实现了一些特殊的功能,比如service间的隔离,避免部署多个service时有可能出现的同名类和库的冲突
知道了原理,就可以推导出解决办法:
为每个service 设置单独的classloader,(实际是为每个service的每个线程设置单独的classloader--Thread Context Class Loader(TCCL))
解决法2: 很简单,在services.xml加下面一句
<parameter name="ServiceTCCL">composite</parameter> 例子:<service name="TestHibernate" scope="application" targetNamespace="http://quickstart.samples/"> <description> TestHibernate Service </description> <messageReceivers> <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-only" class="org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver"/> <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out" class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/> </messageReceivers> <schema schemaNamespace="http://quickstart.samples/xsd"/> <parameter name="ServiceClass">com.machome.test.TestHibernate</parameter> <parameter name="ServiceTCCL">composite</parameter> </service> 部署:
--src---- --webroot-- |--WEB-INF |-classes |-lib |-conf |-modules |-services |-TestHibernate.aar |-TestHibernateAnon.aar |-Student.aar 同时部署多个相互之间没有关系的服务 测试:
http://localhost:8080/axis2/services/TestHibernate/findById?id=2结果:<ns:findByIdResponse><ns:return>mac</ns:return></ns:findByIdResponse>