TomEE、Hazelcast 和 jca-rar
TomEE, Hazelcast and jca-rar
我正在尝试为我的 Hazelcast 缓存添加事务支持。为了完成这个,我发现 Hazelcast 有一个 jca-rar,它给了我一个我可以使用的连接工厂。这是我到目前为止所做的:
- 我已将此
.rar
文件放入我的 WEB-INF/lib
文件夹中。
- 我在
system.properties
文件中设置了tomee.unpack.dir = work/
。
我的 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">
<modelVersion>4.0.0</modelVersion>
<groupId>test</groupId>
<artifactId>cachetest</artifactId>
<version>0.0.1</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<hazelcast.version>3.6.2</hazelcast.version>
</properties>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.5</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<archive>
<manifestEntries>
<Dependencies>com.hazelcast</Dependencies>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast</artifactId>
<version>${hazelcast.version}</version>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast-jca</artifactId>
<version>${hazelcast.version}</version>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast-jca-rar</artifactId>
<version>${hazelcast.version}</version>
<type>rar</type>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>6.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
我添加了一个用于测试目的的休息服务。
@Path("resttest")
@Stateless
public class RestService {
@Resource(mappedName = "hazelcast-jca-rar-3.6.2RA")
private ConnectionFactory connectionFactory;
@GET
@Path("create")
public void createGame() throws ResourceException {
connectionFactory.getConnection();//ClassCastException
}
}
我的web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
<display-name>Cachetest</display-name>
<session-config>
<session-timeout>90</session-timeout>
</session-config>
</web-app>
我的tomee.xml:
<?xml version="1.0" encoding="UTF-8"?>
<tomee>
<Deployments dir="apps" />
</tomee>
这实际上是我在简单测试中的所有代码,当尝试使用 ClassCassException
:
从连接工厂获取连接时它失败了
INFO: HZ Connection Event <<FACTORY_INIT>> for hazelcast.ManagedConnectionFactoryImpl [1] in thread [http-bio-8080-exec-7]
java.lang.Exception: Hz Connection Event Call Stack
at com.hazelcast.jca.ManagedConnectionFactoryImpl.logHzConnectionEvent(ManagedConnectionFactoryImpl.java:167)
at com.hazelcast.jca.ManagedConnectionFactoryImpl.createConnectionFactory(ManagedConnectionFactoryImpl.java:91)
at com.hazelcast.jca.ManagedConnectionFactoryImpl.createConnectionFactory(ManagedConnectionFactoryImpl.java:44)
at org.apache.openejb.core.ConnectorReference.getObject(ConnectorReference.java:50)
at org.apache.openejb.core.ivm.naming.IvmContext.lookup(IvmContext.java:175)
...
SEVERE: EjbTransactionUtil.handleSystemException: com.sun.proxy.$Proxy114 cannot be cast to com.hazelcast.jca.HazelcastConnectionImpl
java.lang.ClassCastException: com.sun.proxy.$Proxy114 cannot be cast to com.hazelcast.jca.HazelcastConnectionImpl
at com.hazelcast.jca.ConnectionFactoryImpl.getConnection(ConnectionFactoryImpl.java:89)
at com.hazelcast.jca.ConnectionFactoryImpl.getConnection(ConnectionFactoryImpl.java:79)
at com.hazelcast.jca.ConnectionFactoryImpl.getConnection(ConnectionFactoryImpl.java:36)
有谁知道为什么会这样?我是否错过了某种配置?
我的 TomEE versjon i 1.7.4 和 hazelcast versjon 3.6.2(用 pom 写的)。
这很糟糕。简而言之:你有麻烦了。
错误描述很清楚:JDK 动态代理无法转换为 class。这是预期的行为,因为 JDK 代理只能实现接口。这是一个特定于 TomEE 的问题,因为大多数主要应用程序服务器供应商使用自定义代理技术并支持 classes(JBoss Javassist、Spring CGLIB 等),而 TomEE 则卡在 JDK 代理。 TomEE 有点承认这个问题,但他们说是 'unlikely to get resolved anytime soon'。有关详细信息,请参阅 there。
Hazelcast 在这里失败的原因是他们将连接对象转换为它的 实现 ,而不是 接口 (参见 source).内部代码的这种行为并没有什么犯罪行为,但有时它并没有派上用场。
现在,进入实践部分。我看不到任何修复它的可能性 'by configuration'。如果您准备好修补 Hazelcast RA,那么您可以将 class 转换替换为基于接口的转换或使用 DissociatableManagedConnection,有人提到它在这种情况下很方便。
public class HazelcastManagedConnectionImpl extends JcaBase
implements ManagedConnection, LocalTransaction,
LocalTransaction, DissociatableManagedConnection {
@Override
public void dissociateConnections() throws ResourceException {
conn = null;
}
...
}
但是,事实上,我建议您重新考虑您的应用程序服务器选择。 TomEE 的市场份额很小并非没有原因:它使用自己的容器来处理几乎所有内容,这使得其开发人员更难将其维护在最新状态。 Wildfly 可能是一个不错的选择(至少,第 9 版非常稳定,我的资源适配器在其中运行良好)。
打开了关于 https://github.com/hazelcast/hazelcast-ra/issues/3 的问题。在 hazelcast 方面修复是微不足道的,所以希望是这样。
编辑:已集成修复程序
我正在尝试为我的 Hazelcast 缓存添加事务支持。为了完成这个,我发现 Hazelcast 有一个 jca-rar,它给了我一个我可以使用的连接工厂。这是我到目前为止所做的:
- 我已将此
.rar
文件放入我的WEB-INF/lib
文件夹中。 - 我在
system.properties
文件中设置了tomee.unpack.dir = work/
。 我的
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"> <modelVersion>4.0.0</modelVersion> <groupId>test</groupId> <artifactId>cachetest</artifactId> <version>0.0.1</version> <packaging>war</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <hazelcast.version>3.6.2</hazelcast.version> </properties> <build> <finalName>${project.artifactId}</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.5</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> <archive> <manifestEntries> <Dependencies>com.hazelcast</Dependencies> </manifestEntries> </archive> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>com.fasterxml.jackson.jaxrs</groupId> <artifactId>jackson-jaxrs-json-provider</artifactId> <version>2.4.3</version> </dependency> <dependency> <groupId>com.hazelcast</groupId> <artifactId>hazelcast</artifactId> <version>${hazelcast.version}</version> </dependency> <dependency> <groupId>com.hazelcast</groupId> <artifactId>hazelcast-jca</artifactId> <version>${hazelcast.version}</version> </dependency> <dependency> <groupId>com.hazelcast</groupId> <artifactId>hazelcast-jca-rar</artifactId> <version>${hazelcast.version}</version> <type>rar</type> </dependency> <dependency> <groupId>javax</groupId> <artifactId>javaee-web-api</artifactId> <version>6.0</version> <scope>provided</scope> </dependency> </dependencies> </project>
我添加了一个用于测试目的的休息服务。
@Path("resttest") @Stateless public class RestService { @Resource(mappedName = "hazelcast-jca-rar-3.6.2RA") private ConnectionFactory connectionFactory; @GET @Path("create") public void createGame() throws ResourceException { connectionFactory.getConnection();//ClassCastException } }
我的web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
<display-name>Cachetest</display-name>
<session-config>
<session-timeout>90</session-timeout>
</session-config>
</web-app>
我的tomee.xml:
<?xml version="1.0" encoding="UTF-8"?>
<tomee>
<Deployments dir="apps" />
</tomee>
这实际上是我在简单测试中的所有代码,当尝试使用 ClassCassException
:
INFO: HZ Connection Event <<FACTORY_INIT>> for hazelcast.ManagedConnectionFactoryImpl [1] in thread [http-bio-8080-exec-7]
java.lang.Exception: Hz Connection Event Call Stack
at com.hazelcast.jca.ManagedConnectionFactoryImpl.logHzConnectionEvent(ManagedConnectionFactoryImpl.java:167)
at com.hazelcast.jca.ManagedConnectionFactoryImpl.createConnectionFactory(ManagedConnectionFactoryImpl.java:91)
at com.hazelcast.jca.ManagedConnectionFactoryImpl.createConnectionFactory(ManagedConnectionFactoryImpl.java:44)
at org.apache.openejb.core.ConnectorReference.getObject(ConnectorReference.java:50)
at org.apache.openejb.core.ivm.naming.IvmContext.lookup(IvmContext.java:175)
...
SEVERE: EjbTransactionUtil.handleSystemException: com.sun.proxy.$Proxy114 cannot be cast to com.hazelcast.jca.HazelcastConnectionImpl
java.lang.ClassCastException: com.sun.proxy.$Proxy114 cannot be cast to com.hazelcast.jca.HazelcastConnectionImpl
at com.hazelcast.jca.ConnectionFactoryImpl.getConnection(ConnectionFactoryImpl.java:89)
at com.hazelcast.jca.ConnectionFactoryImpl.getConnection(ConnectionFactoryImpl.java:79)
at com.hazelcast.jca.ConnectionFactoryImpl.getConnection(ConnectionFactoryImpl.java:36)
有谁知道为什么会这样?我是否错过了某种配置?
我的 TomEE versjon i 1.7.4 和 hazelcast versjon 3.6.2(用 pom 写的)。
这很糟糕。简而言之:你有麻烦了。
错误描述很清楚:JDK 动态代理无法转换为 class。这是预期的行为,因为 JDK 代理只能实现接口。这是一个特定于 TomEE 的问题,因为大多数主要应用程序服务器供应商使用自定义代理技术并支持 classes(JBoss Javassist、Spring CGLIB 等),而 TomEE 则卡在 JDK 代理。 TomEE 有点承认这个问题,但他们说是 'unlikely to get resolved anytime soon'。有关详细信息,请参阅 there。
Hazelcast 在这里失败的原因是他们将连接对象转换为它的 实现 ,而不是 接口 (参见 source).内部代码的这种行为并没有什么犯罪行为,但有时它并没有派上用场。
现在,进入实践部分。我看不到任何修复它的可能性 'by configuration'。如果您准备好修补 Hazelcast RA,那么您可以将 class 转换替换为基于接口的转换或使用 DissociatableManagedConnection,有人提到它在这种情况下很方便。
public class HazelcastManagedConnectionImpl extends JcaBase
implements ManagedConnection, LocalTransaction,
LocalTransaction, DissociatableManagedConnection {
@Override
public void dissociateConnections() throws ResourceException {
conn = null;
}
...
}
但是,事实上,我建议您重新考虑您的应用程序服务器选择。 TomEE 的市场份额很小并非没有原因:它使用自己的容器来处理几乎所有内容,这使得其开发人员更难将其维护在最新状态。 Wildfly 可能是一个不错的选择(至少,第 9 版非常稳定,我的资源适配器在其中运行良好)。
打开了关于 https://github.com/hazelcast/hazelcast-ra/issues/3 的问题。在 hazelcast 方面修复是微不足道的,所以希望是这样。
编辑:已集成修复程序