io.netty netty-all 5.0.0.Alpha2 org.reflections reflections 0.9.11
rpc rpc-common 1.0-SNAPSHOT
package com.hk.common; import java.io.Serializable; /** * 使用JDK的序列化技术必须实现接口Serializable */ public class ClassInfo implements Serializable { private int id; private String className; private String methodName; private Class[] parameterTypes; private Object [] paramters; public int getId() { return id; } public void setId(int id) { this.id = id; } 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[] getParamters() { return paramters; } public void setParamters(Object[] paramters) { this.paramters = paramters; } }
有参接口
package com.hk.common; public interface HasArgsHelloService { String hello(String msg); } 无参接口
package com.hk.common; public interface NoArgsHelloService { String hello(); }
//利用netty创建服务ServerBootstrap,粘合两个NioEventLoopGroup,配置端口ip,设置编码解码信息
package com.hk.rpc.server; import com.hk.rpc.server_stub.RpcServerHandler; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.serialization.ClassResolvers; import io.netty.handler.codec.serialization.ObjectDecoder; import io.netty.handler.codec.serialization.ObjectEncoder; public class RpcServer { public static void main(String[] args) { RpcServer.start("127.0.0.1", 9999); } public static void start(String ip, Integer port) { //创建boss线程组(有点像负责招人的包工头) NioEventLoopGroup boss = new NioEventLoopGroup(); //创建建立链接的线程 NioEventLoopGroup worker = new NioEventLoopGroup(); ServerBootstrap bootstrap = new ServerBootstrap(); try { bootstrap.group(boss, worker) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 128) .childHandler(new ChannelInitializer() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new ObjectEncoder()); ch.pipeline().addLast(new ObjectDecoder(1024 * 64, ClassResolvers.cacheDisabled(null))); ch.pipeline().addLast(new RpcServerHandler()); } }); //bind初始化端口是异步的,但调用sync则会同步阻塞等待端口绑定成功 ChannelFuture future = bootstrap.bind(ip, port).sync(); System.out.println(ip + ":服务已启动,端口为:" + port); future.channel().closeFuture().sync(); } catch (Exception e) { e.printStackTrace(); } finally { boss.shutdownGracefully(); worker.shutdownGracefully(); } } }
//真正通过反射找到实现类,调用方法返回结果
package com.hk.rpc.server_stub;
import com.hk.common.ClassInfo;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import java.lang.reflect.Method;
import java.util.Set;
import org.reflections.Reflections;
public class RpcServerHandler extends ChannelHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//获取调用信息,寻找服务实现类
ClassInfo classInfo = (ClassInfo) msg;
String implName = getImplClassName(classInfo.getClassName());
Class> clazz = Class.forName(implName);
Method method = clazz.getMethod(classInfo.getMethodName(), classInfo.getParameterTypes());
Object result = method.invoke(clazz.newInstance(), classInfo.getParamters());
ctx.writeAndFlush(result);
}
private String getImplClassName(String interfaceName) throws ClassNotFoundException {
Class interClass = Class.forName(interfaceName);
String servicePath = "com.hk.rpc.service";
Reflections reflections = new Reflections(servicePath);
Set
if (implClasses.isEmpty()) {
System.err.println("impl class is not found!");
} else if (implClasses.size() > 1) {
System.err.println("there are many impl classes, not sure invoke which");
} else {
Class[] classes = implClasses.toArray(new Class[1]);
return classes[0].getName();
}
return null;
}
}
package com.hk.rpc.service; import com.hk.common.HasArgsHelloService; public class HasArgsHelloServiceImpl implements HasArgsHelloService { public String hello(String msg) { return "hello "+msg; } }
package com.hk.rpc.service;
import com.hk.common.NoArgsHelloService;
public class NoArgsHelloServiceImpl implements NoArgsHelloService {
public String hello() {
return "hello";
}
}
客户端代码
//利用代理类来测试流程
package com.hk.rpc.server; import com.hk.common.HasArgsHelloService; import com.hk.common.NoArgsHelloService; import com.hk.rpc.client_stub.RpcProxy; public class RPCClient { public static void main(String[] args){ NoArgsHelloService noArgsHelloService = (NoArgsHelloService) RpcProxy.create(NoArgsHelloService.class); System.out.println(noArgsHelloService.hello()); HasArgsHelloService hasArgsHelloService = (HasArgsHelloService) RpcProxy.create(HasArgsHelloService.class); System.out.println(hasArgsHelloService.hello("hello 黄凯!")); } }
客户端处理器代码
//接收到服务端的请求,并赋值以及关闭连接
package com.hk.rpc.client_stub; import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerContext; public class RpcClientHandler extends ChannelHandlerAdapter { /** * RPC调用返回的结果 */ private Object rpcResult; public Object getRpcResult() { return rpcResult; } public void setRpcResult(Object rpcResult) { this.rpcResult = rpcResult; } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { setRpcResult(msg); ctx.close(); } }
客户端代码类
//根据接口类信息通过jdk代理来调用实现类,在Bootstrap建立连接后,添加客户端处理器,并返回信息
package com.hk.rpc.client_stub; import com.hk.common.ClassInfo; import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.serialization.ClassResolvers; import io.netty.handler.codec.serialization.ObjectDecoder; import io.netty.handler.codec.serialization.ObjectEncoder; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class RpcProxy { public static Object create(final Class clazz) { return Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //构造调用信息 ClassInfo classInfo = new ClassInfo(); classInfo.setClassName(clazz.getName()); classInfo.setMethodName(method.getName()); classInfo.setParameterTypes(method.getParameterTypes()); classInfo.setParamters(args); //使用netty发送调用信息给服务提供方 NioEventLoopGroup group = new NioEventLoopGroup(); // Bootstrap bootstrap = new Bootstrap(); final RpcClientHandler rpcClientHandler = new RpcClientHandler(); try { bootstrap.group(group) .channel(NioSocketChannel.class) .option(ChannelOption.SO_KEEPALIVE, true) .option(ChannelOption.TCP_NODELAY, true) .handler(new ChannelInitializer() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new ObjectEncoder()); //反序列化对象时指定类解析器,null表示使用默认的类加载器 ch.pipeline().addLast(new ObjectDecoder(1024 * 64, ClassResolvers.cacheDisabled(null))); ch.pipeline().addLast(rpcClientHandler); } }); //connect是异步的,但调用其future的sync则是同步等待连接成功 ChannelFuture future = bootstrap.connect("127.0.0.1", 9999).sync(); //同步等待调用信息发送成功 future.channel().writeAndFlush(classInfo).sync(); //同步等待RPCClientHandler的channelRead被触发后(意味着收到了调用结果) future.channel().closeFuture().sync(); } catch (Exception e) { e.printStackTrace(); } finally { group.shutdownGracefully(); } //返回调用结果 return rpcClientHandler.getRpcResult(); } }); } }
最后测试,先启动RpcServer服务类,打印了信息之后,再启动客户端RPCClient进行测试
测试结果如下:
hello
hello hello 黄凯!
测试成功!!!