我有一个用于Web服务的EJB的EAR应用程序,部署在Glassfish 3.0.1服务器上。所有依赖项都由maven加载,关于pom.xml。我使用wsimport从WSDL文件生成类。一切都很完美。
然后由于一些性能问题,我不得不为mybatis查询实现缓存。在我打开缓存之后,我意识到,我的类需要可序列化。这不是问题。
<xs:annotation>
<xs:appinfo>
<jaxb:globalBindings>
<xjc:serializable uid="1" />
</jaxb:globalBindings>
</xs:appinfo>
</xs:annotation>
应用程序已编译和部署,但是当我从soapUI第二次调用Web服务操作(第一次ok,cache为空)时,我收到以下错误。
org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: org.apache.ibatis.cache.CacheException: Error deserializing object. Cause: java.lang.ClassNotFoundException: cz.cpost.esb.cenik.schema.CountryType
### Cause: org.apache.ibatis.cache.CacheException: Error deserializing object. Cause: java.lang.ClassNotFoundException: cz.cpost.esb.cenik.schema.CountryType
... some code ommited ...
Caused by: org.apache.ibatis.cache.CacheException: Error deserializing object. Cause: java.lang.ClassNotFoundException: cz.cpost.esb.cenik.schema.CountryType
at org.apache.ibatis.cache.decorators.SerializedCache.deserialize(SerializedCache.java:79)
at org.apache.ibatis.cache.decorators.SerializedCache.getObject(SerializedCache.java:35)
at org.apache.ibatis.cache.decorators.LoggingCache.getObject(LoggingCache.java:35)
at org.apache.ibatis.cache.decorators.SynchronizedCache.getObject(SynchronizedCache.java:40)
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:56)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:78)
... 83 more
Caused by: java.lang.ClassNotFoundException: cz.cpost.esb.cenik.schema.CountryType
at com.sun.enterprise.loader.ASURLClassLoader.findClassData(ASURLClassLoader.java:713)
at com.sun.enterprise.loader.ASURLClassLoader.findClass(ASURLClassLoader.java:626)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:247)
at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:604)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1575)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1496)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1732)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
at java.util.ArrayList.readObject(ArrayList.java:593)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:974)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1849)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
at org.apache.ibatis.cache.decorators.SerializedCache.deserialize(SerializedCache.java:76)
... 88 more
似乎当app试图从缓存中获取数据时,找不到对象CountryType。 我不知道这是怎么可能的,我在maven和缓存方面都很新。
maven构建元素:
<build>
<resources>
<resource>
<targetPath>META-INF/wsdl</targetPath>
<directory>src/wsdl</directory>
<includes/>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes/>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<compilerArguments>
<endorseddirs>${endorsed.dir}</endorseddirs>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ejb-plugin</artifactId>
<version>2.3</version>
<configuration>
<ejbVersion>3.1</ejbVersion>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>1.12</version>
<executions>
<execution>
<goals>
<goal>wsimport</goal>
</goals>
<configuration>
<keep>true</keep>
<wsdlFiles>
<wsdlFile>CenikServices-v2.0.wsdl</wsdlFile>
</wsdlFiles>
<packageName>cz.cpost.esb.cenik.schema</packageName>
<staleFile>${project.build.directory}/jaxws/stale/cenik.stale</staleFile>
<bindingFiles>
<bindingFile>${basedir}/src/main/resources/jaxb-bindings.xml</bindingFile>
</bindingFiles>
</configuration>
<id>wsimport-generate-cenik</id>
<phase>generate-sources</phase>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>javax.xml</groupId>
<artifactId>webservices-api</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
<configuration>
<sourceDestDir>${project.build.directory}/generated-sources/jaxws-wsimport</sourceDestDir>
<destDir>${project.build.directory}/classes</destDir>
<xnocompile>true</xnocompile>
<verbose>true</verbose>
<extension>true</extension>
<catalog>${basedir}/src/jax-ws-catalog.xml</catalog>
<target>2.0</target>
</configuration>
</plugin>
</plugins>
</build>
映射器配置中的缓存配置:
<cache type="org.mybatis.caches.ehcache.EhcacheCache">
<property name="timeToIdleSeconds" value="7200"/>
<property name="timeToLiveSeconds" value="28800"/>
<property name="maxElementsInMemory" value="5000"/>
<property name="maxElementsOnDisk" value="10000"/>
<property name="memoryStoreEvictionPolicy" value="LRU"/>
</cache>
我虽然我的源代码不在classpath中,但我将archive元素放到了ear pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>cz.cpost.esb</groupId>
<artifactId>cenikservices-ear</artifactId>
<version>2.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ear</artifactId>
<packaging>ear</packaging>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>cenikservices-ejb</artifactId>
<version>${project.version}</version>
<type>ejb</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<version>2.5</version>
<configuration>
<defaultLibBundleDir>lib</defaultLibBundleDir>
<modules>
<ejbModule>
<groupId>${project.groupId}</groupId>
<artifactId>cenikservices-ejb</artifactId>
</ejbModule>
</modules>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
EAR文件结构:
但问题没有解决。为什么应用程序无法找到打包在cenikservices-ejb-2.0.jar中的生成源?
更新
我将EJB类的行添加到构造函数
中import org.apache.ibatis.io.Resources;
...
public CenikEJB() {
Resources.setDefaultClassLoader(this.getClass().getClassLoader()); // added
this.sqlSessionFactory = MyBatisConnectionFactory.getSqlSessionFactory();
}
但仍然在ASURLClassLoader上得到相同的错误:-( 我测试过,如果类的CountryType在EJB方法中可用,那么它是。我在日志中看到 SUCCESS 。
@Override
public List<CountryType> listCountry(Integer codeTask, String langAlfaCode) throws CenikFault {
methodName = "Cenik.listCountry";
SqlSession session = this.sqlSessionFactory.openSession();
try {
this.getClass().getClassLoader().loadClass("cz.cpost.esb.cenik.schema.CountryType");
ccpLogger.info( "SUCCESS - Pokus o nalezeni tridy CountryType vysel");
} catch (ClassNotFoundException ex) {
ccpLogger.info("FAIL - Pokus o nalezeni tridy CountryType nevysel",ex);
}
try
{
ListCountryType param = this.of.createListCountryType();
param.setCodeTask(codeTask);
param.setLangAlfaCode(langAlfaCode);
// ziskat seznam zemi pomoci SQL procedury
List seznamZemi = session.selectList("Cenik.getListCountry", param);
return seznamZemi;
} catch (IllegalArgumentException ex) {
ccpLogger.error(methodName,ex);
...
} catch (Exception ex) {
ccpLogger.error(methodName,ex);
...
} finally {
session.close();
}
}
答案 0 :(得分:2)
问题是服务器端无法加载类cz.cpost.esb.cenik.schema.CountryType
。
最可能的原因是定义该类的JAR文件无法包含在您部署的EAR文件中。最可能的解释是,EAR项目的POM文件没有所需形式的必需依赖项。
请注意,依赖项应列在POM文件顶层的<dependencies>
元素中;即作为<project>
元素的子元素。
第一步应该是检查包含该类的JAR文件是否实际位于已部署的webapp中。 (事实上,问题就是其他问题......)
然后,您需要将必需的依赖项添加到EAR模块的POM文件中。
<强>更新强>
根据您提供的其他信息,我认为这是Ibatis课程加载的问题。似乎Ibatis正在尝试使用不包含您的类的类加载器来加载类。 (我的猜测是Ibatis正在使用“公共类”类加载器......它不包括你的应用程序JAR。)
显然,修复是在servlet类中执行此操作:
import com.ibatis.common.resources.Resources;
...
Resources.setDefaultClassLoader(this.getClass().getClassLoader());
参考文献:
更新#2
我在这一点上猜...但是这个错误报告(http://code.google.com/p/mybatis/issues/detail?id=622)似乎描述了MyBatis 3.x中setDefaultClassLoader
无法正常工作的错误。他们似乎在说“在3.2.2中修复”。我注意到你使用的是3.0.5。看看将POM的依赖关系更新到更高版本是否有帮助。
如果没有,我建议的最好的方法是将一个调试器附加到您的Glassfish实例,看看是否可以挖掘出它正在使用的类加载器......以及为什么。很明显, 是一个类加载器问题。