如何在Jakarta EE 9中创建适配微服务的合规JCA资源适配器(.rar)
构建Jakarta EE 9兼容的JCA资源适配器(RAR)连接内存数据网格
以下是适配微服务场景、符合Jakarta EE 9规范的JCA资源适配器构建步骤,基于JCA 2.0规范(Jakarta EE 9对应的JCA版本):
一、核心组件梳理
JCA适配器必须包含以下核心组件,缺一不可:
- ManagedConnectionFactory:核心工厂类,负责创建与内存数据网格的物理连接实例,处理地址、认证等配置参数
- ManagedConnection:管理物理连接的生命周期,封装与内存数据网格的实际交互逻辑
- ConnectionFactory:暴露给业务代码的客户端接口,用于获取连接实例
- Connection:业务层直接调用的连接接口,封装内存数据网格的操作(如get/put)
- ResourceAdapter:适配器入口,定义启动、停止等生命周期回调
- ra.xml:部署描述符,声明适配器元数据、组件映射、默认配置
二、代码实现步骤
1. 依赖配置(Maven示例)
使用Jakarta EE 9命名空间的依赖,同时引入目标内存数据网格的客户端SDK:
<dependencies> <!-- Jakarta JCA 2.0 API --> <dependency> <groupId>jakarta.resource</groupId> <artifactId>jakarta.resource-api</artifactId> <version>2.0.0</version> <scope>provided</scope> </dependency> <!-- 以Hazelcast内存网格为例,替换为你的目标网格客户端 --> <dependency> <groupId>com.hazelcast</groupId> <artifactId>hazelcast</artifactId> <version>5.3.6</version> <scope>compile</scope> </dependency> </dependencies>
2. 核心组件代码实现
(1)定义业务层接口
封装内存数据网格的操作,让业务代码无需感知底层实现:
// 业务层使用的连接接口 public interface IMDGConnection { Object get(String key); void put(String key, Object value); void close(); } // 连接工厂接口 public interface IMDGConnectionFactory { IMDGConnection getConnection() throws ResourceException; }
(2)实现ManagedConnectionFactory
处理配置参数,创建物理连接实例:
import jakarta.resource.annotation.ConnectionFactoryDefinition; import jakarta.resource.annotation.ConnectionFactoryDefinitions; import jakarta.resource.ResourceException; import jakarta.resource.spi.ManagedConnection; import jakarta.resource.spi.ManagedConnectionFactory; import jakarta.resource.spi.ConnectionManager; import java.io.Serializable; @ConnectionFactoryDefinitions({ @ConnectionFactoryDefinition( name = "java:/IMDGConnectionFactory", interfaceName = "com.example.IMDGConnectionFactory", resourceAdapter = "imdg-ra" ) }) public class IMDGManagedConnectionFactory implements ManagedConnectionFactory, Serializable { // 可配置的内存网格地址参数 private String imdgServerAddress = "localhost:5701"; @Override public Object createConnectionFactory(ConnectionManager cm) throws ResourceException { return cm.createConnectionFactory(this); } @Override public ManagedConnection createManagedConnection(Subject subject, ConnectionRequestInfo cri) throws ResourceException { // 创建物理连接实例 return new IMDGManagedConnection(imdgServerAddress); } // 实现equals、hashCode,以及getter/setter方法 @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; IMDGManagedConnectionFactory that = (IMDGManagedConnectionFactory) obj; return imdgServerAddress.equals(that.imdgServerAddress); } @Override public int hashCode() { return imdgServerAddress.hashCode(); } public String getImdgServerAddress() { return imdgServerAddress; } public void setImdgServerAddress(String imdgServerAddress) { this.imdgServerAddress = imdgServerAddress; } }
(3)实现ManagedConnection
管理物理连接的生命周期,处理会话:
import com.hazelcast.client.HazelcastClient; import com.hazelcast.client.config.ClientConfig; import com.hazelcast.core.HazelcastInstance; import jakarta.resource.ResourceException; import jakarta.resource.spi.*; import java.util.ArrayList; import java.util.List; import java.util.Set; public class IMDGManagedConnection implements ManagedConnection { private final HazelcastInstance hazelcastInstance; private final List<IMDGConnection> connectionHandles = new ArrayList<>(); private final ConnectionEventSupport eventSupport = new ConnectionEventSupport(this); public IMDGManagedConnection(String serverAddress) { // 初始化与内存网格的物理连接 ClientConfig config = new ClientConfig(); config.getNetworkConfig().addAddress(serverAddress); this.hazelcastInstance = HazelcastClient.newHazelcastClient(config); } @Override public Object getConnection(Subject subject, ConnectionRequestInfo cri) throws ResourceException { // 创建业务层连接句柄 IMDGConnection connection = new IMDGConnectionImpl(this); connectionHandles.add(connection); return connection; } @Override public void cleanup() throws ResourceException { // 回收业务层连接句柄,保留物理连接 connectionHandles.clear(); } @Override public void destroy() throws ResourceException { // 关闭物理连接 hazelcastInstance.shutdown(); } @Override public void addConnectionEventListener(ConnectionEventListener listener) { eventSupport.addConnectionEventListener(listener); } @Override public void removeConnectionEventListener(ConnectionEventListener listener) { eventSupport.removeConnectionEventListener(listener); } // 暴露给业务层连接的操作方法 public Object get(String key) { return hazelcastInstance.getMap("default").get(key); } public void put(String key, Object value) { hazelcastInstance.getMap("default").put(key, value); } // 其他接口方法实现(如getLogWriter、setLogWriter等) @Override public void setLogWriter(java.io.PrintWriter out) throws ResourceException {} @Override public java.io.PrintWriter getLogWriter() throws ResourceException { return null; } @Override public XAResource getXAResource() throws ResourceException { return null; } @Override public LocalTransaction getLocalTransaction() throws ResourceException { return null; } @Override public ManagedConnectionMetaData getMetaData() throws ResourceException { return null; } }
(4)实现业务层连接句柄
封装物理连接的调用,处理关闭逻辑:
public class IMDGConnectionImpl implements IMDGConnection { private final IMDGManagedConnection managedConnection; private boolean closed = false; public IMDGConnectionImpl(IMDGManagedConnection managedConnection) { this.managedConnection = managedConnection; } @Override public Object get(String key) { checkClosed(); return managedConnection.get(key); } @Override public void put(String key, Object value) { checkClosed(); managedConnection.put(key, value); } @Override public void close() { if (!closed) { closed = true; managedConnection.cleanup(); } } private void checkClosed() { if (closed) { throw new IllegalStateException("Connection has been closed"); } } }
(5)实现ResourceAdapter
定义适配器的生命周期回调:
import jakarta.resource.ResourceAdapterInternalException; import jakarta.resource.spi.BootstrapContext; import jakarta.resource.spi.ResourceAdapter; import jakarta.resource.spi.endpoint.MessageEndpointFactory; import java.io.Serializable; public class IMDGResourceAdapter implements ResourceAdapter, Serializable { @Override public void start(BootstrapContext ctx) throws ResourceAdapterInternalException { // 适配器启动时的初始化逻辑,如加载全局配置 } @Override public void stop() { // 适配器停止时的清理逻辑 } // 其他接口方法实现(适配消息驱动场景,若仅用于连接则返回空实现) @Override public void endpointActivation(MessageEndpointFactory factory, ActivationSpec spec) throws ResourceException {} @Override public void endpointDeactivation(MessageEndpointFactory factory, ActivationSpec spec) {} @Override public XAResource[] getXAResources(ActivationSpec[] specs) throws ResourceException { return new XAResource[0]; } }
3. 编写部署描述符ra.xml
放在src/main/resources/META-INF目录下,符合Jakarta EE 9规范:
<?xml version="1.0" encoding="UTF-8"?> <connector xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/connector_2_0.xsd" version="2.0"> <display-name>IMDG Resource Adapter</display-name> <vendor-name>Example Corp</vendor-name> <eis-type>In-Memory Data Grid</eis-type> <resourceadapter> <resourceadapter-class>com.example.IMDGResourceAdapter</resourceadapter-class> <managedconnectionfactory-class>com.example.IMDGManagedConnectionFactory</managedconnectionfactory-class> <config-property> <config-property-name>imdgServerAddress</config-property-name> <config-property-type>java.lang.String</config-property-type> <config-property-value>localhost:5701</config-property-value> </config-property> <connection-definition> <managedconnectionfactory-class>com.example.IMDGManagedConnectionFactory</managedconnectionfactory-class> <connectionfactory-interface>com.example.IMDGConnectionFactory</connectionfactory-interface> <connection-interface>com.example.IMDGConnection</connection-interface> </connection-definition> </resourceadapter> </connector>
三、微服务场景适配要点
- 轻量打包:剔除冗余依赖,使用内存网格的轻量客户端版本,控制RAR体积
- 配置外置化:支持通过环境变量、Kubernetes ConfigMap等覆盖ra.xml中的配置,适配动态部署
- 健康检查:在ResourceAdapter的
start方法中添加连接校验逻辑,或暴露健康检查端点,配合微服务治理平台做存活探针 - 连接池优化:配置合理的连接池参数(最大连接数、空闲超时),适配微服务短连接、高并发的特点
- 可观察性:集成SLF4J日志、Micrometer指标,监控连接状态与操作性能
四、打包与测试
1. 打包RAR
使用Maven的maven-rar-plugin打包:
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-rar-plugin</artifactId> <version>3.0.0</version> <executions> <execution> <goals> <goal>rar</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
执行mvn package生成target/imdg-ra.rar
2. 部署测试
- 在Jakarta EE 9兼容的服务器(如Payara 6、WildFly 26+)部署RAR
- 在微服务中注入连接工厂并测试:
import jakarta.ejb.Stateless; import jakarta.annotation.Resource; import jakarta.resource.ResourceException; @Stateless public class IMDGService { @Resource(lookup = "java:/IMDGConnectionFactory") private IMDGConnectionFactory connectionFactory; public void storeData(String key, Object value) throws ResourceException { try (IMDGConnection conn = connectionFactory.getConnection()) { conn.put(key, value); } } public Object retrieveData(String key) throws ResourceException { try (IMDGConnection conn = connectionFactory.getConnection()) { return conn.get(key); } } }
内容的提问来源于stack exchange,提问作者Tarun Patel
相关产品推荐
相关产品推荐

