rpc netty
来源:互联网 发布:mac怎么在pdf上写字 编辑:程序博客网 时间:2024/05/24 04:44
RPC框架比如dubbo,主体实现大概是,客户端与服务端商定使用同一种传输协议,服务端接受客户端的连接,
客户端使用动态代理,根据不同的协议生成 不同的代理类,代理类中就是协议的客户端实现。服务器的地址
2netty管道处理编码解码
3 服务端
5 测试
客户端
客户端使用动态代理,根据不同的协议生成 不同的代理类,代理类中就是协议的客户端实现。服务器的地址
和端口可以使用注册中心来通知。下面使用netty来简单实现。
1、请求、响应封装类,使用jdk的序列化,序列化工具类
package com.rpc.msg;import java.io.Serializable;import java.util.Arrays;public class RequestMsg implements Serializable {/** * */private static final long serialVersionUID = 1L;private String requestId;private String className;private String methodName;private Class<?>[] parameterTypes;private Object[] parameters;public String getRequestId() {return requestId;}public void setRequestId(String requestId) {this.requestId = requestId;}public String getClassName() {return className;}public void setClassName(String className) {this.className = className;}public String getMethodName() {return methodName;}public void setMethodName(String methodName) {this.methodName = methodName;}public Class<?>[] getParameterTypes() {return parameterTypes;}public void setParameterTypes(Class<?>[] parameterTypes) {this.parameterTypes = parameterTypes;}public Object[] getParameters() {return parameters;}public void setParameters(Object[] parameters) {this.parameters = parameters;}@Overridepublic String toString() {return "RequestMsg [requestId=" + requestId + ", className=" + className + ", methodName=" + methodName+ ", parameterTypes=" + Arrays.toString(parameterTypes) + ", parameters=" + Arrays.toString(parameters)+ "]";}}
package com.rpc.msg;import java.io.Serializable;public class ResponseMsg implements Serializable{/** * */private static final long serialVersionUID = 1L; private String requestId; private Object result;public String getRequestId() {return requestId;}public void setRequestId(String requestId) {this.requestId = requestId;}public Object getResult() {return result;}public void setResult(Object result) {this.result = result;} }
package com.rpc.util;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;public class SerializationUtil {public static <T> byte[] serialize(T obj) {if (obj == null) {return null;}ByteArrayOutputStream bo = new ByteArrayOutputStream();ObjectOutputStream oo;try {oo = new ObjectOutputStream(bo);oo.writeObject(obj);return bo.toByteArray();} catch (IOException e) {e.printStackTrace();}return null;}@SuppressWarnings("unchecked")public static <T> T deserialize(byte[] objBytes, Class<T> cls) {if (objBytes == null || objBytes.length == 0) {return null;}ByteArrayInputStream bi = new ByteArrayInputStream(objBytes);ObjectInputStream oi;try {oi = new ObjectInputStream(bi);return (T) oi.readObject();} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}return null;}}
2netty管道处理编码解码
package com.rpc.ende;import com.rpc.util.SerializationUtil;import io.netty.buffer.ByteBuf;import io.netty.channel.ChannelHandlerContext;import io.netty.handler.codec.MessageToByteEncoder;public class RpcEncoder extends MessageToByteEncoder<Object>{private Class<?> genericClass; public RpcEncoder(Class<?> genericClass) { this.genericClass = genericClass; } @Override public void encode(ChannelHandlerContext ctx, Object in, ByteBuf out) throws Exception { if (genericClass.isInstance(in)) { byte[] data = SerializationUtil.serialize(in); out.writeInt(data.length); out.writeBytes(data); } }}
package com.rpc.ende;import java.util.List;import com.rpc.util.SerializationUtil;import io.netty.buffer.ByteBuf;import io.netty.channel.ChannelHandlerContext;import io.netty.handler.codec.ByteToMessageDecoder;public class RpcDecoder extends ByteToMessageDecoder {private Class<?> genericClass;public RpcDecoder(Class<?> genericClass) {this.genericClass = genericClass;}@Overridepublic void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {if (in.readableBytes() < 4) {return;}in.markReaderIndex();int dataLength = in.readInt();if (dataLength < 0) {ctx.close();}if (in.readableBytes() < dataLength) {in.resetReaderIndex();return;}byte[] data = new byte[dataLength];in.readBytes(data);Object obj = SerializationUtil.deserialize(data, genericClass);out.add(obj);}}
3 服务端
ProviderServer 容器初始化完成后,找到所有业务接口的实现类,启动netty服务器
RpcService用来标识接口实现类,在spring容器中的bean
NettyServer启动netty服务器,接受管道传来的request,使用反射处理得到结果,写回管道
NettyServerHandler处理request的过程
package com.rpc.provider;import java.util.HashMap;import java.util.Map;import org.springframework.beans.BeansException;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import com.rpc.provider.transation.NettyServer;public class ProviderServer implements ApplicationContextAware{private NettyServer nettyServer;public void setApplicationContext(ApplicationContext ctx) throws BeansException {Map<String, Object> handlerMap = new HashMap<String, Object>();Map<String, Object> serviceBeanMap = ctx.getBeansWithAnnotation(RpcService.class); if (serviceBeanMap.values() != null) { for (Object serviceBean : serviceBeanMap.values()) { String interfaceName = serviceBean.getClass().getAnnotation(RpcService.class).value().getName(); handlerMap.put(interfaceName, serviceBean); } }nettyServer.setHandlerMap(handlerMap);try {nettyServer.start();} catch (Exception e) {e.printStackTrace();}}public void setNettyServer(NettyServer nettyServer) {this.nettyServer = nettyServer;}}
package com.rpc.provider;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import org.springframework.stereotype.Component;@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Component public @interface RpcService {Class<?> value();}
package com.rpc.provider.transation;import java.util.Map;import com.rpc.ende.RpcDecoder;import com.rpc.ende.RpcEncoder;import com.rpc.msg.RequestMsg;import com.rpc.msg.ResponseMsg;import io.netty.bootstrap.ServerBootstrap;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelInitializer;import io.netty.channel.ChannelOption;import io.netty.channel.EventLoopGroup;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.SocketChannel;import io.netty.channel.socket.nio.NioServerSocketChannel;public class NettyServer {private String serverAddress;private Map<String,Object> handlerMap;public NettyServer(String serverAddress) {super();this.serverAddress = serverAddress;}public void setHandlerMap(Map<String, Object> handlerMap) {this.handlerMap = handlerMap;}public void start() throws Exception{EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel channel) throws Exception { channel.pipeline() .addLast(new RpcDecoder(RequestMsg.class)) .addLast(new RpcEncoder(ResponseMsg.class)) .addLast(new NettyServerHandler(handlerMap)); } }) .option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true); String[] array = serverAddress.split(":"); String host = array[0]; int port = Integer.parseInt(array[1]); ChannelFuture future = bootstrap.bind(host, port).sync(); future.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); }}}
package com.rpc.provider.transation;import java.lang.reflect.InvocationTargetException;import java.util.Map;import org.springframework.cglib.reflect.FastClass;import org.springframework.cglib.reflect.FastMethod;import com.rpc.msg.RequestMsg;import com.rpc.msg.ResponseMsg;import io.netty.channel.ChannelFutureListener;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.SimpleChannelInboundHandler;public class NettyServerHandler extends SimpleChannelInboundHandler<RequestMsg> {private Map<String,Object> handlerMap;public NettyServerHandler(Map<String, Object> handlerMap) {super();this.handlerMap = handlerMap;}@Overrideprotected void channelRead0(ChannelHandlerContext ctx, RequestMsg request) throws Exception {ResponseMsg response = new ResponseMsg();response.setRequestId(request.getRequestId());try {Object result = handle(request);response.setResult(result);} catch (Throwable t) {response.setResult(t);}ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);}private Object handle(RequestMsg request) throws InvocationTargetException {String className = request.getClassName();Object serviceBean = handlerMap.get(className);Class<?> serviceClass = serviceBean.getClass();String methodName = request.getMethodName();Class<?>[] parameterTypes = request.getParameterTypes();Object[] parameters = request.getParameters();/* * Method method = serviceClass.getMethod(methodName, parameterTypes); * method.setAccessible(true); * return method.invoke(serviceBean,parameters); */FastClass serviceFastClass = FastClass.create(serviceClass);FastMethod serviceFastMethod = serviceFastClass.getMethod(methodName, parameterTypes);return serviceFastMethod.invoke(serviceBean, parameters);}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {ctx.close();}}
RpcProxy生成接口代理类方法,具体实现需要根据传输协议,使用jdk动态代理
NettyClient 客户端连接服务器,发送请求,得到响应,使用CountDownLatch阻塞线程
ConsumerService为了使用方便,将配置的接口,使用RpcProxy生成代理类,注册到spring容器中
package com.rpc.consumer;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.util.UUID;import com.rpc.consumer.transation.NettyClient;import com.rpc.msg.RequestMsg;import com.rpc.msg.ResponseMsg;public class RpcProxy {private String serverAddress;public RpcProxy(String serverAddress) { this.serverAddress = serverAddress; }@SuppressWarnings("unchecked") public <T> T create(Class<?> interfaceClass) { return (T) Proxy.newProxyInstance( interfaceClass.getClassLoader(), new Class<?>[]{interfaceClass}, new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { RequestMsg request = new RequestMsg(); request.setRequestId(UUID.randomUUID().toString()); request.setClassName(method.getDeclaringClass().getName()); request.setMethodName(method.getName()); request.setParameterTypes(method.getParameterTypes()); request.setParameters(args); String[] array = serverAddress.split(":"); String host = array[0]; int port = Integer.parseInt(array[1]); NettyClient client = new NettyClient(host, port); ResponseMsg response = client.send(request); return response.getResult(); } } ); }}
package com.rpc.consumer.transation;import java.util.concurrent.CountDownLatch;import com.rpc.ende.RpcDecoder;import com.rpc.ende.RpcEncoder;import com.rpc.msg.RequestMsg;import com.rpc.msg.ResponseMsg;import io.netty.bootstrap.Bootstrap;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.ChannelInitializer;import io.netty.channel.ChannelOption;import io.netty.channel.EventLoopGroup;import io.netty.channel.SimpleChannelInboundHandler;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.SocketChannel;import io.netty.channel.socket.nio.NioSocketChannel;public class NettyClient extends SimpleChannelInboundHandler<ResponseMsg>{private String host; private int port;public NettyClient(String host, int port) {super();this.host = host;this.port = port;}private CountDownLatch cdt = new CountDownLatch(1);private ResponseMsg responseMsg;public ResponseMsg send(RequestMsg request) throws Exception { EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group).channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel channel) throws Exception { channel.pipeline() .addLast(new RpcEncoder(RequestMsg.class)) .addLast(new RpcDecoder(ResponseMsg.class)) .addLast(NettyClient.this); } }) .option(ChannelOption.SO_KEEPALIVE, true); ChannelFuture future = bootstrap.connect(host, port).sync(); future.channel().writeAndFlush(request).sync(); cdt.await(); if (responseMsg != null) { future.channel().closeFuture().sync(); } return responseMsg; } finally { group.shutdownGracefully(); } }@Overrideprotected void channelRead0(ChannelHandlerContext arg0, ResponseMsg arg1) throws Exception {responseMsg = arg1;cdt.countDown();}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {ctx.close();}}
package com.rpc.consumer;import java.util.List;import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.context.ConfigurableApplicationContext;public class ConsumerService implements ApplicationContextAware{private RpcProxy rpcProxy;public void setRpcProxy(RpcProxy rpcProxy) {this.rpcProxy = rpcProxy;}private List<String> clsNames;public ConsumerService(List<String> clsNames) {super();this.clsNames = clsNames;}public void setApplicationContext(ApplicationContext arg0) throws BeansException {ConfigurableApplicationContext cac = (ConfigurableApplicationContext) arg0;ConfigurableListableBeanFactory beanFactory = cac.getBeanFactory();for (String string : clsNames) {try {Class<?> interfaceClass = Class.forName(string);Object singletonObject = rpcProxy.create(interfaceClass);beanFactory.registerSingleton(string, singletonObject);} catch (ClassNotFoundException e) {e.printStackTrace();continue;}}}}
5 测试
测试接口及实现
App服务器端启动类
application-provider.xml服务器配置文件
package test;public interface HelloService { String hi(String name);}
package test.server;import com.rpc.provider.RpcService;import test.HelloService;@RpcService(HelloService.class)public class HelloServiceImpl implements HelloService {public String hi(String name) {return "hi " + name;}}
package test.server;import org.springframework.context.support.ClassPathXmlApplicationContext;public class App {@SuppressWarnings("resource")public static void main(String[] args) {new ClassPathXmlApplicationContext("application-provider.xml");}}
<?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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop--4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx--4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <context:component-scan base-package="test"/> <bean id="nettyServer" class="com.rpc.provider.transation.NettyServer"> <constructor-arg name="serverAddress" value="127.0.0.1:8000"/> </bean> <bean id="providerServer" class="com.rpc.provider.ProviderServer"> <property name="nettyServer" ref="nettyServer"></property> </bean></beans>
客户端
application-consumer.xml
<?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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop--4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx--4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <bean id="rpcProxy" class="com.rpc.consumer.RpcProxy"> <constructor-arg name="serverAddress" value="127.0.0.1:8000"/> </bean> <bean id="providerServer" class="com.rpc.consumer.ConsumerService"> <constructor-arg name="clsNames"> <list> <value>test.HelloService</value> </list> </constructor-arg> <property name="rpcProxy" ref="rpcProxy"></property> </bean></beans>
package test.client;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import test.HelloService;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations = "application-consumer.xml")public class HelloServiceTest {@Autowiredprivate HelloService helloService;@Testpublic void test1(){System.out.println(helloService.hi("world"));}}
0 0
- rpc netty
- Netty-RPC
- Netty RPC框架
- netty rpc 框架
- RPC与netty
- Netty RPC demo 试跑
- Netty实现简单RPC
- RPC学习----------netty实现通讯
- RPC与Netty是什么鬼
- spark2.0 rpc.netty.Dispatcher
- 3. [netty-RPC]--服务端程序设计
- Spark RPC之Netty启动
- Netty 实现简单RPC调用
- 基于netty的rpc框架
- RPC框架与Netty框架
- netty rpc 方面demo 调研
- netty-protobuf-rpc与protobuf-socket-rpc互通
- Triple is an RPC framework(Netty,ZooKeeper)
- QBC对数据库查询
- CodeForces
- Unsupervised dimensionality reduction via PCA
- bzoj 1937: [Shoi2004]Mst 最小生成树 (KM算法)
- 数据结构-归并排序
- rpc netty
- opencv笔记(2):图像形态学
- Java内存分配分析
- 链接脚本简介
- linux压缩与解压命令
- java 使用 comet4j 主动向客户端推送信息 简单例子
- hdu 2853 Assignment (KM算法)
- PHP文件写入函数file_put_contents并发追加写入丢失内容问题解决方法
- Java编程思想-03操作符