public class RpcClient { private static final Logger LOGGER = LoggerFactory.getLogger(RpcClient.class); private QueueConnection qConnection; private QueueSession qSession; private Queue requestQ; private Queue responseQ; public RpcClient(String rpcFactory, String rpcRequest, String rpcResponse) { try { Context ctx = new InitialContext(); QueueConnectionFactory factory = (QueueConnectionFactory) ctx.lookup(rpcFactory); qConnection = factory.createQueueConnection(); qSession = qConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); requestQ = (Queue) ctx.lookup(rpcRequest); responseQ = (Queue) ctx.lookup(rpcResponse); qConnection.start(); } catch (Exception e) { LOGGER.error("init rpcproxy error", e); } } public <T> T create(final Class<?> interfaceClass) { return create(interfaceClass, ""); } @SuppressWarnings("unchecked") public <T> T create(final Class<?> interfaceClass, final String serviceVersion) { return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class<?>[] { interfaceClass }, new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { RpcRequest request = new RpcRequest(); request.setRequestId(UUID.randomUUID().toString()); request.setInterfaceName(method.getDeclaringClass().getName()); request.setServiceVersion(serviceVersion); request.setMethodName(method.getName()); request.setParameterTypes(method.getParameterTypes()); request.setParameters(args); BytesMessage requestMessage = qSession.createBytesMessage(); requestMessage.writeBytes(SerializationUtil.serialize(request)); requestMessage.setJMSReplyTo(responseQ); QueueSender qsender = qSession.createSender(requestQ); qsender.send(requestMessage); String filter = "JMSCorrelationID = '" + requestMessage.getJMSMessageID() + "'"; QueueReceiver qReceiver = qSession.createReceiver(responseQ, filter); BytesMessage responseMessage = (BytesMessage) qReceiver.receive(30000); byte messByte[] = new byte[(int) responseMessage.getBodyLength()]; responseMessage.readBytes(messByte); RpcResponse rpcResponse = SerializationUtil.deserialize(messByte, RpcResponse.class); if (rpcResponse.hasException()) { throw rpcResponse.getException(); } else { return rpcResponse.getResult(); } } }); } }
public class RpcRequest { private String requestId; private String interfaceName; private String serviceVersion; private String methodName; private Class<?>[] parameterTypes; private Object[] parameters; //Omit get and set methods }
public class RpcResponse{ private String requestId; private Exception exception; private Object result; //Omit get and set methods }
public class RpcServer implements ApplicationContextAware, InitializingBean { private static final Logger LOGGER = LoggerFactory.getLogger(RpcServer.class); private QueueConnection qConnection; private QueueSession qSession; private Queue requestQ; private String rpcFactory; private String rpcRequest; /** *Store the mapping relationship between service name and service object */ private Map<String, Object> serviceMap = new HashMap<String, Object>(); public RpcServer(String rpcFactory, String rpcRequest) { this.rpcFactory = rpcFactory; this.rpcRequest = rpcRequest; } @Override public void afterPropertiesSet() throws Exception { try { Context ctx = new InitialContext(); QueueConnectionFactory factory = (QueueConnectionFactory) ctx.lookup(rpcFactory); qConnection = factory.createQueueConnection(); qSession = qConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); requestQ = (Queue) ctx.lookup(rpcRequest); qConnection.start(); QueueReceiver receiver = qSession.createReceiver(requestQ); receiver.setMessageListener(new RpcMessageListener(qSession, serviceMap)); LOGGER.info("ready receiver message"); } catch (Exception e) { if (qConnection != null) { try { qConnection.close(); } catch (JMSException e1) { } } LOGGER.error("server start error", e); } } @Override public void setApplicationContext(ApplicationContext ctx) throws BeansException { Map<String, Object> serviceBeanMap = ctx.getBeansWithAnnotation(RpcService.class); if (serviceBeanMap != null && serviceBeanMap.size() > 0) { for (Object serviceBean : serviceBeanMap.values()) { RpcService rpcService = serviceBean.getClass().getAnnotation(RpcService.class); String serviceName = rpcService.value().getName(); String serviceVersion = rpcService.version(); if (serviceVersion != null && !serviceVersion.equals("")) { serviceName += "-" + serviceVersion; } serviceMap.put(serviceName, serviceBean); } } } }
public class RpcMessageListener implements MessageListener { private static final Logger LOGGER = LoggerFactory.getLogger(RpcMessageListener.class); private QueueSession qSession; /** *Store the mapping relationship between service name and service object */ private Map<String, Object> serviceMap = new HashMap<String, Object>(); public RpcMessageListener(QueueSession qSession, Map<String, Object> serviceMap) { this.qSession = qSession; this.serviceMap = serviceMap; } @Override public void onMessage(Message message) { try { LOGGER.info("receiver message : " + message.getJMSMessageID()); RpcResponse response = new RpcResponse(); BytesMessage responeByte = qSession.createBytesMessage(); responeByte.setJMSCorrelationID(message.getJMSMessageID()); QueueSender sender = qSession.createSender((Queue) message.getJMSReplyTo()); try { BytesMessage byteMessage = (BytesMessage) message; byte messByte[] = new byte[(int) byteMessage.getBodyLength()]; byteMessage.readBytes(messByte); RpcRequest rpcRequest = SerializationUtil.deserialize(messByte, RpcRequest.class); response.setRequestId(rpcRequest.getRequestId()); String serviceName = rpcRequest.getInterfaceName(); String serviceVersion = rpcRequest.getServiceVersion(); if (serviceVersion != null && !serviceVersion.equals("")) { serviceName += "-" + serviceVersion; } Object serviceBean = serviceMap.get(serviceName); if (serviceBean == null) { throw new RuntimeException(String.format("can not find service bean by key: %s", serviceName)); } Class<?> serviceClass = serviceBean.getClass(); String methodName = rpcRequest.getMethodName(); Class<?>[] parameterTypes = rpcRequest.getParameterTypes(); Object[] parameters = rpcRequest.getParameters(); Method method = serviceClass.getMethod(methodName, parameterTypes); method.setAccessible(true); Object result = method.invoke(serviceBean, parameters); response.setResult(result); } catch (Exception e) { response.setException(e); LOGGER.error("onMessage error", e); } responeByte.writeBytes(SerializationUtil.serialize(response)); sender.send(responeByte); } catch (Exception e) { LOGGER.error("send message error", e); } } }
public interface IHelloService { String hello(String name); }
java.naming.factory.initial=org.apache.activemq.jndi.ActiveMQInitialContextFactory java.naming.provider.url= tcp://localhost:61616 java.naming.security.principal=system java.naming.security.credentials=manager connectionFactoryNames=RPCFactory queue.RPCRequest=jms.RPCRequest queue.RPCResponse=jms.RPCResponse
<? xml version="1.0" encoding="UTF-8"?> <beans xmlns=" http://www.springframework.org/schema/beans " xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance " xmlns:context=" http://www.springframework.org/schema/context " xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd "> <context:component-scan base-package="zh.rpc.jms.test.server.impl" /> <context:property-placeholder location="classpath:jms.properties" /> <bean id="rpcServer" class="zh.rpc.jms.server.RpcServer"> <constructor-arg name="rpcFactory" value="${rpc.rpc_factory}" /> <constructor-arg name="rpcRequest" value="${rpc.rpc_request}" /> </bean> </beans>
@RpcService(IHelloService.class) public class HelloServiceImpl implements IHelloService { @Override public String hello(String name) { return "REQ+" + name; } }
<? xml version="1.0" encoding="UTF-8"?> <beans xmlns=" http://www.springframework.org/schema/beans " xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance " xmlns:context=" http://www.springframework.org/schema/context " xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd "> <context:property-placeholder location="classpath:jms.properties" /> <bean id="rpcProxy" class="zh.rpc.jms.client.RpcClient"> <constructor-arg name="rpcFactory" value="${rpc.rpc_factory}" /> <constructor-arg name="rpcRequest" value="${rpc.rpc_request}" /> <constructor-arg name="rpcResponse" value="${rpc.rpc_response}" /> </bean> </beans>
public class ClientTest { private static ApplicationContext context; public static void main(String[] args) throws Exception { context = new ClassPathXmlApplicationContext("spring-client.xml"); RpcClient rpcProxy = context.getBean(RpcClient.class); IHelloService helloService = rpcProxy.create(IHelloService.class); String result = helloService.hello("World"); System.out.println(result); System.exit(0); } }
REQ+World