目录
项目结构
主要分为服务端, 客户端, 通用类以及序列化类
客户端:
1. 客户端调用目标方法
2. 使用动态代理封装Request请求对象(服务类名, 方法名称, 参数类型名称数组, 参数值数组)
3. 向服务端发送请求, 等待服务端执行完毕返回结果
4. 获取结果, 输出服务端:
1. 服务端启动时注册目标服务的实例对象
2. 接收到客户端的请求信息后, 利用反射执行目标方法
3. 目标方法执行完成, 封装Response对象, 返回
序列化类信息
序列化接口
作用: 定义序列化, 反序列化方法
package com.lic.demo.rpc.cust.serialize;
public interface Serializer {
public <T> Object deserialize(byte[] bytes, Class<T> clazz) ;
public <T> byte[] serialize(T obj);
}
序列化实现类
作用: 实现序列化逻辑
package com.lic.demo.rpc.cust.serialize;
import com.lic.demo.rpc.v1.common.RpcException;
import com.lic.demo.rpc.v1.common.RpcRequest;
import io.protostuff.LinkedBuffer;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.Schema;
import io.protostuff.runtime.RuntimeSchema;
import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ProtobufSerializer implements Serializer {
private static Objenesis objenesis = new ObjenesisStd(true);
private static Map<Class<?>, Schema<?>> cachedSchema = new ConcurrentHashMap<Class<?>, Schema<?>>();
private static <T> Schema<T> getSchema(Class<T> cls) {
@SuppressWarnings("unchecked")
Schema<T> schema = (Schema<T>) cachedSchema.get(cls);
if (schema == null) {
schema = RuntimeSchema.createFrom(cls);
if (schema != null) {
cachedSchema.put(cls, schema);
}
}
return schema;
}
@Override
public <T> byte[] serialize(T obj) {
@SuppressWarnings("unchecked")
Class<T> cls = (Class<T>) obj.getClass();
LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
try {
Schema<T> schema = getSchema(cls);
return ProtostuffIOUtil.toByteArray(obj, schema, buffer);
} catch (Exception e) {
throw new RpcException(e.getMessage(), e);
} finally {
buffer.clear();
}
}
@Override
public <T> Object deserialize(byte[] bytes, Class<T> clazz) {
try {
T message = objenesis.newInstance(clazz);
Schema<T> schema = getSchema(clazz);
ProtostuffIOUtil.mergeFrom(bytes, message, schema);
return message;
} catch (Exception e) {
throw new RpcException(e.getMessage(), e);
}
}
public static void main(String[] args) {
RpcRequest request = new RpcRequest();
request.setMethodName("add");
request.setParam1(1.0);
request.setParam2(3.0);
ProtobufSerializer sr = new ProtobufSerializer();
byte[] bytes = sr.serialize(request);
System.out.println(bytes.length);
RpcRequest rr = (RpcRequest) sr.deserialize(bytes, RpcRequest.class);
System.out.println(rr.toString());
}
}
序列化工厂类
package com.lic.demo.rpc.cust.serialize;
import com.lic.demo.rpc.v1.serialize.ProtobufSerializer;
import com.lic.demo.rpc.v1.serialize.Serializer;
public class SerializerFactory {
public static Serializer getSerializer() {
return new ProtobufSerializer();
}
}
通用类信息
服务接口类
作用: 定义方法信息
package com.lic.demo.rpc.cust.common;
public interface CalculatorService {
double add(double op1, double op2, double op3);
double substract(double op1, double op2);
double multiply(double op1, double op2);
}
Class工具类
作用: 根据类型名称生成对应的Class对象
package com.lic.demo.rpc.cust.common;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class ClassUtils {
private static final Logger logger = LoggerFactory.getLogger(ClassUtils.class);
private static final Map<String, Class<?>> PRIMITIVE_CLASS = new HashMap<String, Class<?>>(1024);
private static final Map<String, Class<?>> CLASS_CACHE = new HashMap<String, Class<?>>(1024);
private static final Map<String, Method> METHOD_CACHE = new HashMap<String, Method>(1024);
static {
PRIMITIVE_CLASS.put("boolean", boolean.class);
PRIMITIVE_CLASS.put("byte", byte.class);
PRIMITIVE_CLASS.put("short", short.class);
PRIMITIVE_CLASS.put("int", int.class);
PRIMITIVE_CLASS.put("long", long.class);
PRIMITIVE_CLASS.put("float", float.class);
PRIMITIVE_CLASS.put("double", double.class);
PRIMITIVE_CLASS.put("char", char.class);
PRIMITIVE_CLASS.put("void", void.class);
CLASS_CACHE.putAll(PRIMITIVE_CLASS);
}
public static Class<?> getClass(String className) throws ClassNotFoundException {
Class<?> clazz = CLASS_CACHE.get(className);
if (null != clazz) {
return clazz;
}
synchronized (CLASS_CACHE) {
if (null == CLASS_CACHE.get(className)) {
clazz = PRIMITIVE_CLASS.get(className);
if (null == clazz) {
clazz = Class.forName(className);
}
CLASS_CACHE.put(className, clazz);
return clazz;
} else {
return CLASS_CACHE.get(className);
}
}
}
}
RPC请求解码类
作用: 对获取到请求信息进行反序列化
package com.lic.demo.rpc.cust.common;
import com.lic.demo.rpc.v1.serialize.Serializer;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import java.util.List;
public class RpcDecode extends ByteToMessageDecoder {
private Class<?> genericClass;
private Serializer serializer;
public RpcDecode(Class<?> genericClass, Serializer serializer) {
this.genericClass = genericClass;
this.serializer = serializer;
}
@Override
public final 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 = serializer.deserialize(data, genericClass);
out.add(obj);
}
}
RPC请求编码类
作用: 对封装的请求信息进行序列化, 以便进行网络传输
package com.lic.demo.rpc.cust.common;
import com.lic.demo.rpc.v1.serialize.Serializer;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
public class RpcEncode extends MessageToByteEncoder<Object> {
private Class<?> genericClass;
private Serializer serializer;
public RpcEncode(Class<?> genericClass, Serializer serializer) {
this.genericClass = genericClass;
this.serializer = serializer;
}
@Override
protected void encode(ChannelHandlerContext ctx, Object in, ByteBuf out) throws Exception {
if (genericClass.isInstance(in)) {
byte[] data = serializer.serialize(in);
out.writeInt(data.length);
out.writeBytes(data);
}
}
}
自定义异常类
作用: 封装异常信息
package com.lic.demo.rpc.cust.common;
public class RpcException extends RuntimeException {
public RpcException(String msg) {
super(msg);
}
public RpcException(String message, Exception e) {
super(message, e);
}
}
RPC请求类
作用: 封装请求信息(请求唯一标识, 服务类名称, 目标方法名称, 参数类型名称数组, 参数值数组)
package com.lic.demo.rpc.cust.common;
import java.util.Arrays;
public class RpcRequest {
private String id;
private String serviceName;
private String methodName;
private transient Class<?>[] parameterTypes; //add: {double.class, double.class}
private String[] parameterTypeNames; //add: {"double", "double"}
private Object[] args;
public RpcRequest() {
super();
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getServiceName() {
return serviceName;
}
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
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 String[] getParameterTypeNames() {
return parameterTypeNames;
}
public void setParameterTypeNames(String[] parameterTypeNames) {
this.parameterTypeNames = parameterTypeNames;
}
public Object[] getArgs() {
return args;
}
public void setArgs(Object[] args) {
this.args = args;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(args);
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((methodName == null) ? 0 : methodName.hashCode());
result = prime * result + Arrays.hashCode(parameterTypeNames);
result = prime * result + ((serviceName == null) ? 0 : serviceName.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
RpcRequest other = (RpcRequest) obj;
if (!Arrays.equals(args, other.args))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (methodName == null) {
if (other.methodName != null)
return false;
} else if (!methodName.equals(other.methodName))
return false;
if (!Arrays.equals(parameterTypeNames, other.parameterTypeNames))
return false;
if (serviceName == null) {
if (other.serviceName != null)
return false;
} else if (!serviceName.equals(other.serviceName))
return false;
return true;
}
@Override
public String toString() {
return "RpcRequestv1_1 [id=" + id + ", serviceName=" + serviceName + ", methodName=" + methodName
+ ", parameterTypeNames=" + Arrays.toString(parameterTypeNames) + ", args=" + Arrays.toString(args)
+ "]";
}
}
RPC Response类
作用: 封装服务端返回的结果信息(唯一标识, 方法名称, 结果)
package com.lic.demo.rpc.cust.common;
public class RpcResponse {
private String id;
private String methodName;
private String cause;
private double result;
public RpcResponse() {
super();
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public String getCause() {
return cause;
}
public void setCause(String cause) {
this.cause = cause;
}
public double getResult() {
return result;
}
public void setResult(double result) {
this.result = result;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((cause == null) ? 0 : cause.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((methodName == null) ? 0 : methodName.hashCode());
long temp;
temp = Double.doubleToLongBits(this.result);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
RpcResponse other = (RpcResponse) obj;
if (cause == null) {
if (other.cause != null)
return false;
} else if (!cause.equals(other.cause))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (methodName == null) {
if (other.methodName != null)
return false;
} else if (!methodName.equals(other.methodName))
return false;
if (Double.doubleToLongBits(result) != Double.doubleToLongBits(other.result))
return false;
return true;
}
@Override
public String toString() {
return "RpcResponse [id=" + id + ", methodName=" + methodName + ", cause=" + cause + ", result=" + result + "]";
}
}
服务端类信息
服务实现类
作用: 业务逻辑实现
package com.lic.demo.rpc.cust.server;
import com.lic.demo.rpc.v1_2.CalculatorService;
public class CalculatorServiceImpl implements CalculatorService {
@Override
public double add(double op1, double op2) {
return op1 + op2;
}
@Override
public double substract(double op1, double op2) {
return op1 - op2;
}
@Override
public double multiply(double op1, double op2) {
return op1 * op2;
}
}
RPC服务维护类
作用: 在服务端发布服务, 维护服务类
package com.lic.demo.rpc.cust.server;
import com.lic.demo.rpc.cust.common.ClassUtils;
import com.lic.demo.rpc.cust.common.RpcException;
import com.lic.demo.rpc.cust.common.RpcRequest;
import com.lic.demo.rpc.cust.common.RpcResponse;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class RpcBuilder {
Map<String, Object> services = new ConcurrentHashMap();
Map<String, Class<?>> interfaces = new ConcurrentHashMap();
/**
* 发布服务
* @param serviceInterface 服务接口
* @param service 服务实例
*/
public void publishService(Class<?> serviceInterface, Object service) {
if (services.containsKey(serviceInterface.getName()) || interfaces.containsKey(serviceInterface.getName())) {
throw new RpcException("serviceInterface has been already registered......");
}
if (!(serviceInterface.isInstance(service))) {
throw new RpcException("service object must implement the service Interface .......");
}
services.put(serviceInterface.getName(), service);
interfaces.put(serviceInterface.getName(), serviceInterface);
}
public RpcResponse invokeService(RpcRequest rpcRequest) {
String serviceName = rpcRequest.getServiceName(); //获取服务类名
String methodName = rpcRequest.getMethodName(); //获取方法名称
Class<?> serviceInterface = interfaces.get(serviceName); //根据服务名称获取目标接口
String[] parameterTypeNames = rpcRequest.getParameterTypeNames(); //获取参数类型名称
Method m;
Object result = null;
/**
* 根据参数类型名称生成参数类型数组, 后面根据此数组可以选择指定的方法
*/
Class<?>[] parameterClasses = new Class<?>[parameterTypeNames.length];
try {
for (int i = 0; i < parameterClasses.length; i++) {
parameterClasses[i] = ClassUtils.getClass(parameterTypeNames[i]);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
/**
* 根据方法名称以及参数类型数组选择目标方法
*/
m = serviceInterface.getMethod(methodName, parameterClasses);
/**
* 执行目标方法
*/
result = m.invoke(services.get(serviceName), rpcRequest.getArgs());
} catch (Exception e) {
e.printStackTrace();
}
/**
* 封装response对象
*/
RpcResponse response = new RpcResponse();
response.setId(rpcRequest.getId());
response.setMethodName(methodName);
response.setResult((Double) result);
return response;
}
}
服务端类
作用: 启动网络服务, 等待客户端请求信息
package com.lic.demo.rpc.cust.server;
import com.lic.demo.rpc.cust.common.RpcDecode;
import com.lic.demo.rpc.cust.common.RpcEncode;
import com.lic.demo.rpc.cust.common.RpcRequest;
import com.lic.demo.rpc.cust.common.RpcResponse;
import com.lic.demo.rpc.cust.serialize.SerializerFactory;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class NettyServer {
private static final Logger logger = LoggerFactory.getLogger(NettyServer.class);
private Thread thread;
private final int port;
public NettyServer(int port) {
this.port = port;
}
public void start(final RpcBuilder rpcBuilder) throws Exception {
thread = new Thread(new Runnable() {
@Override
public void run() {
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 RpcDecode(RpcRequest.class, SerializerFactory.getSerializer()))
.addLast(new RpcEncode(RpcResponse.class, SerializerFactory.getSerializer()))
.addLast(new NettyServerHandler(rpcBuilder));
}
})
.option(ChannelOption.SO_TIMEOUT, 100)
.option(ChannelOption.SO_BACKLOG, 128)
.option(ChannelOption.TCP_NODELAY, true)
.option(ChannelOption.SO_REUSEADDR, true)
.childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture future = bootstrap.bind(port).sync();
logger.info("接口服务器端启动成功......");
Channel serviceChannel = future.channel().closeFuture().sync().channel();
} catch (InterruptedException e) {
logger.error(e.getMessage(), e);
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
});
thread.start();
}
public Thread getThread() {
return this.thread;
}
public void stop() throws Exception {
if (thread!=null && thread.isAlive()) {
thread.interrupt();
}
logger.info("接口服务器端停止......");
}
}
服务端处理器类
作用: 当客户端请求到达时调用调用服务维护类解析请求
package com.lic.demo.rpc.cust.server;
import com.lic.demo.rpc.cust.common.RpcRequest;
import com.lic.demo.rpc.cust.common.RpcResponse;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class NettyServerHandler extends SimpleChannelInboundHandler<RpcRequest> {
private static final Logger logger = LoggerFactory.getLogger(NettyServerHandler.class);
private RpcBuilder rpcBuilder;
public NettyServerHandler(RpcBuilder rpcBuilder) {
this.rpcBuilder = rpcBuilder;
}
@Override
public void channelRead0(final ChannelHandlerContext ctx, RpcRequest rpcRequest) throws Exception {
/**
* 解析Request请求信息, 执行目标方法
*/
RpcResponse rpcResponse = rpcBuilder.invokeService(rpcRequest);
//返回执行结果
ctx.writeAndFlush(rpcResponse);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
ctx.close();
}
}
服务端测试类
作用: 开启服务
package com.lic.demo.rpc.cust.server;
import com.lic.demo.rpc.v1_1.server.NettyServer;
import com.lic.demo.rpc.v1_1.server.RpcBuilder;
import com.lic.demo.rpc.v1_2.CalculatorService;
import com.lic.demo.rpc.v1_2.CalculatorServiceImpl;
public class RpcDemoServer {
public static void main(String[] args) {
/**
* 创建RpcBuilder对象
* 该对象用于发布服务信息以及通过反射调用服务方法
*/
RpcBuilder builder = new RpcBuilder();
//发布服务
builder.publishService(CalculatorService.class, new CalculatorServiceImpl());
//创建服务端, 启动
NettyServer server = new NettyServer(8080);
try {
server.start(builder);
} catch (Exception e) {
e.printStackTrace();
}
}
}
客户端类信息
JDK动态代理Handler类
作用: 生成代理类逻辑, 包装请求信息, 发送请求
package com.lic.demo.rpc.cust.client;
import com.lic.demo.rpc.v1_1.client.NettyClient;
import com.lic.demo.rpc.v1_1.common.RpcRequest;
import com.lic.demo.rpc.v1_1.common.RpcResponse;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.SynchronousQueue;
public class JDKInvocationHandler implements InvocationHandler {
private NettyClient client;
private Class<?> proxyClass;
public JDKInvocationHandler(Class<?> proxyClass, NettyClient client) {
this.proxyClass = proxyClass;
this.client = client;
}
@Override
public Object invoke(Object proxy, Method method, Object[] paramValues) throws Throwable {
String methodName = method.getName();
Class<?>[] paramTypes = method.getParameterTypes();
/**
* 如果执行的是toString(), hashCode(), equals()方法,则调用原方法
*/
if ("toString".equals(methodName) && paramTypes.length == 0) {
return client.toString();
} else if ("hashCode".equals(methodName) && paramTypes.length == 0) {
return client.hashCode();
} else if ("equals".equals(methodName) && paramTypes.length == 1) {
Object another = paramValues[0];
return proxy == another || (proxy.getClass().isInstance(another) && client.equals(parseInvoker(another)));
}
/**
* 根据目标方法信息封装Request请求信息
*/
RpcRequest request = buildRequest(proxyClass.getName(), method, paramValues);
/**
* 发送RPC请求, 让服务端执行目标方法
*/
RpcResponse response = sendRPCRequest(request);
return response.getResult();
}
private RpcResponse sendRPCRequest(RpcRequest request) {
//创建同步队列, 等待返回数据
SynchronousQueue<RpcResponse> queue = new SynchronousQueue();
NettyClient.putSunchronousQuee(request.getId(), queue);
RpcResponse response = null;
try {
/**
* 客户端发送请求
*/
client.sendRpcRequest(request);
/**
* 等待服务器端返回数据, 然后客户端处理器会将返回的response对象放入同步对列中
*/
response = queue.take();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return response;
}
public static NettyClient parseInvoker(Object proxyObject) {
InvocationHandler handler = java.lang.reflect.Proxy.getInvocationHandler(proxyObject);
if (handler instanceof JDKInvocationHandler) {
return ((JDKInvocationHandler) handler).getProxyInvoker();
}
return null;
}
public Class<?> getProxyClass() {
return proxyClass;
}
public NettyClient getProxyInvoker() {
return client;
}
private RpcRequest buildRequest(String serviceName, Method method, Object[] args) {
/**
* 包装Request
*/
String id = UUID.randomUUID().toString();
RpcRequest request = new RpcRequest();
request.setServiceName(serviceName);
request.setId(id);
request.setMethodName(method.getName());
request.setArgs(args); //设置参数值
//遍历所有参数, 获取参数类型集合
List<String> parameterTypes = new ArrayList<String>();
for (Class<?> parameterType : method.getParameterTypes()) {
parameterTypes.add(parameterType.getName());
}
//参数类型信息
request.setParameterTypeNames(parameterTypes.toArray(new String[0]));
return request;
}
}
代理工厂类
作用: 生成代理类
package com.lic.demo.rpc.cust.client;
import com.lic.demo.rpc.v1_1.client.NettyClient;
import com.lic.demo.rpc.v1_2.JDKInvocationHandler;
import java.lang.reflect.InvocationHandler;
public final class ProxyFactory {
/**
* 使用JDK动态代理创建代理对象
*/
public static <T> T getProxy(Class<T> interfaceClass, NettyClient proxyInvoker) {
/**
* 1. 创建Handler, 增强逻辑
*/
InvocationHandler handler = new JDKInvocationHandler(interfaceClass, proxyInvoker);
/**
* 2. 获取类加载器
*/
ClassLoader classLoader = ProxyFactory.class.getClassLoader();
/**
* 3. 获取代理对象
*/
T proxy = (T) java.lang.reflect.Proxy.newProxyInstance(classLoader,new Class[] { interfaceClass }, handler);
return proxy;
}
}
客户端类
package com.lic.demo.rpc.cust.client;
import com.lic.demo.rpc.v1.common.RpcDecode;
import com.lic.demo.rpc.v1.common.RpcEncode;
import com.lic.demo.rpc.v1.serialize.Serializer;
import com.lic.demo.rpc.v1_1.common.RpcRequest;
import com.lic.demo.rpc.v1_1.common.RpcResponse;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
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.NioSocketChannel;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.SynchronousQueue;
public class NettyClient {
private static ConcurrentHashMap<String, SynchronousQueue<RpcResponse>> mapInfo = new ConcurrentHashMap();
public static void putSunchronousQuee(String id, SynchronousQueue<RpcResponse> queue) {
mapInfo.put(id, queue);
}
public static SynchronousQueue<RpcResponse> getSynchronousQueue(String id) {
return mapInfo.get(id);
}
public static void removeById(String id) {
mapInfo.remove(id);
}
public void sendRpcRequest(RpcRequest rpcRequest) throws Exception {
try {
this.channel.writeAndFlush(rpcRequest).sync();
} catch (Exception e) {
throw e;
}
}
private Channel channel;
public void init(String host, int port, final Serializer serializer) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
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 RpcEncode(RpcRequest.class, serializer))
.addLast(new RpcDecode(RpcResponse.class, serializer))
.addLast(new NettyClientHandler());
}
})
.option(ChannelOption.TCP_NODELAY, true)
.option(ChannelOption.SO_REUSEADDR, true)
.option(ChannelOption.SO_KEEPALIVE, true);
this.channel = bootstrap.connect(host, port).sync().channel();
System.out.println("接口服务端连接成功......");
}
public boolean isValidate() {
if (this.channel != null) {
return this.channel.isActive();
}
return false;
}
public void close() {
if (this.channel != null) {
if (this.channel.isOpen()) {
this.channel.close();
}
}
}
}
客户端处理器类
作用: 接收服务器端返回的结果
package com.lic.demo.rpc.cust.client;
import com.lic.demo.rpc.v1_1.common.RpcResponse;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.SynchronousQueue;
public class NettyClientHandler extends SimpleChannelInboundHandler<RpcResponse> {
private static final Logger logger = LoggerFactory.getLogger(NettyClientHandler.class);
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
logger.error("远程连接异常:", cause);
ctx.close();
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, RpcResponse rpcResponse) throws Exception {
String id = rpcResponse.getId();
/**
* 将从接收到服务器返回的结果放入同步对列中
*/
SynchronousQueue<RpcResponse> synchronousQueue = NettyClient.getSynchronousQueue(id);
synchronousQueue.put(rpcResponse);
NettyClient.removeById(id);
}
}
客户端测试类
作用: 连接服务端, 执行目标方法
package com.lic.demo.rpc.cust.client;
import com.lic.demo.rpc.v1.common.SerializerFactory;
import com.lic.demo.rpc.v1_1.client.NettyClient;
import com.lic.demo.rpc.v1_2.CalculatorService;
import com.lic.demo.rpc.v1_2.ProxyFactory;
public class RpcDemoClient {
public static void main(String[] args) throws Exception {
// 创建客户端
NettyClient client = new NettyClient();
// 初始化客户端
client.init("127.0.0.1", 8080, SerializerFactory.getSerializer());
/**
* 获取代理类
*/
CalculatorService service = ProxyFactory.getProxy(CalculatorService.class, client);
/**
* 执行目标方法
*/
System.out.println(service.add(1.0, 156.0));
client.close();
}
}
配置文件信息
pom文件
<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>
<artifactId>netty</artifactId>
<name>learning-netty</name>
<groupId>com.turingschool.demo</groupId>
<version>1.0.0</version>
<packaging>jar</packaging>
<url>http://www.waylau.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<slf4j-api.version>1.7.25</slf4j-api.version>
<protobuf.version>3.6.1</protobuf.version>
<os-maven-plugin.version>1.5.0.Final</os-maven-plugin.version>
<protobuf-maven-plugin.version>0.5.0</protobuf-maven-plugin.version>
<junit.version>4.12</junit.version>
</properties>
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>${os-maven-plugin.version}</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>${protobuf-maven-plugin.version}</version>
<configuration>
<protocArtifact>
com.google.protobuf:protoc:3.6.1:exe:${os.detected.classifier}
</protocArtifact>
<pluginId>protoc-java</pluginId>
<protoSourceRoot>${project.basedir}/src/main/resources</protoSourceRoot>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<optimize>true</optimize>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.jboss.marshalling/jboss-marshalling -->
<dependency>
<groupId>org.jboss.marshalling</groupId>
<artifactId>jboss-marshalling</artifactId>
<version>2.0.6.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.jboss.marshalling/jboss-marshalling-serial -->
<dependency>
<groupId>org.jboss.marshalling</groupId>
<artifactId>jboss-marshalling-serial</artifactId>
<version>2.0.6.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.30.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.protostuff/protostuff-core -->
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-core</artifactId>
<version>1.6.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.protostuff/protostuff-runtime -->
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-runtime</artifactId>
<version>1.6.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.protostuff/protostuff-api -->
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-api</artifactId>
<version>1.6.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.objenesis/objenesis -->
<dependency>
<groupId>org.objenesis</groupId>
<artifactId>objenesis</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
<version>${protobuf.version}</version>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j-api.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/jul-to-slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>1.7.25</version>
</dependency>
</dependencies>
</project>