2

我有一个用于 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 服务操作(第一次正常,缓存为空)时,出现以下错误。

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

似乎当应用程序尝试从缓存中获取数据时,找不到对象 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>

我虽然我的源不在类路径中,但我将归档元素放入耳 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文件结构:

已部署 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(); 
    } 
}
4

1 回答 1

2

问题是服务器端无法加载类cz.cpost.esb.cenik.schema.CountryType

最可能的原因是定义该类的 JAR 文件不能包含在您部署的 EAR 文件中。最可能的解释是 EAR 项目的 POM 文件没有所需形式的所需依赖项。

请注意,依赖项应列在<dependencies>POM 文件顶层的元素中;即作为元素的子<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 实例,看看您是否可以找出它正在使用的类加载器......以及为什么。很明显这一个类加载器问题。

于 2013-06-07T09:28:17.883 回答