RPC,Remote Procedure Call,远程过程调用,是一种通过网络从远程计算机上请求服务,而不需要了解底层网络技术的协议。
我们这里要定义一个 RPC 框架,这个框架提供给用户后,用户只需要按照使用步骤就可以完成 RPC 远程调用。我们现在给出用户的使用步骤:
1、 用户需要将业务接口通知到 Server 与 Client,因为业务接口是服务名称。
2、 用户只需将业务接口的实现类写入到 Server 端的指定包下,那么这个包下的实现类就会被 Server 发布。
3、 Client 端只需根据业务接口名就可获取到 Server 端发布的服务提供者,然后就可以调用到远程 Server 端的实现类方法的执行。
1、rpc-api包
业务接口:
/**
* 业务接口
*/
public interface SomeService {
String hello(String name);
}
客户端发送给服务端的服务调用信息:
/**
* 客户端发送给服务端的服务调用信息
*/
@Data
public class Invocation implements Serializable {
// 接口名,即服务名称
private String className;
// 远程调用的方法名
private String methodName;
// 方法参数类型
private Class<?>[] paramTypes;
// 方法参数值
private Object[] paramValues;
}
2、rpc-server包
业务接口的实现类写入到 Server 端的指定包下:
package com.rpc.server.service;
import com.rpc.api.SomeService;
public class SomeServiceImpl implements SomeService {
@Override
public String hello(String name) {
return "你好:"+name;
}
}
服务端启动:
public class RpcServerStarter {
public static void main(String[] args) throws Exception {
RpcServer server = new RpcServer();
server.publish("com.rpc.server.service");
server.start();
}
}
rpc服务端:
public class RpcServer {
// 注册表
private Map<String, Object> registerMap = new HashMap<>();
// 用于缓存指定包下的实现类的类名
private List<String> classCache = new ArrayList<>();
// 线程安全的list
// private List classCache = Collections.synchronizedList(new ArrayList<>());
// 将接口名(服务名称)与指定包中的实现类的实例进行对应,即写入到一个map
public void publish(String basePackage) throws Exception {
// 将指定包中的实现类的类名写入到classCache中
cacheProviderClass(basePackage);
// 真正的注册
doRegister();
}
private void cacheProviderClass(String basePackage) {
URL resource = this.getClass().getClassLoader()
// 将包名的.转为/
.getResource(basePackage.replaceAll("\\.", "/"));
// 若目录中没有任何资源,则直接结束
if(resource == null) return;
// 将URL资源转换为File
File dir = new File(resource.getFile());
// 遍历指定包及其子孙包中所有文件,查找.class文件
for (File file : dir.listFiles()) {
if (file.isDirectory()) {
cacheProviderClass(basePackage + "." + file.getName());
} else if (file.getName().endsWith(".class")) {
String fileName = file.getName().replace(".class", "").trim();
classCache.add(basePackage + "." + fileName);
}
}
System.out.println(classCache);
}
private void doRegister() throws Exception {
if (classCache.size() == 0) {
return;
}
// 遍历缓存中的所有类
for(String className : classCache) {
Class<?> clazz = Class.forName(className);
// 获取接口名
String interfaceName = clazz.getInterfaces()[0].getName();
registerMap.put(interfaceName, clazz.newInstance());
}
}
// 启动Netty Server
public void start() throws InterruptedException {
EventLoopGroup parentGroup = new NioEventLoopGroup();
EventLoopGroup childGroup = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(parentGroup, childGroup)
// 用于指定,当服务端的请求处理线程全部用完时,
// 临时存放已经完成了三次握手的请求的队列的最大长度。
.option(ChannelOption.SO_BACKLOG, 1024)
// 指定是否启用心跳机制来维护长连接的不被清除
.childOption(ChannelOption.SO_KEEPALIVE, true)
// 指定要创建Channel的类型
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// 添加编码器
pipeline.addLast(new ObjectEncoder());
// 添加解码器
pipeline.addLast(new ObjectDecoder(Integer.MAX_VALUE,
ClassResolvers.cacheDisabled(null)));
// 添加自定义处理器
pipeline.addLast(new RpcServerHandler(registerMap));
}
});
ChannelFuture future = bootstrap.bind(8888).sync();
System.out.println("微服务已经注册完成。。。");
future.channel().closeFuture().sync();
} finally {
parentGroup.shutdownGracefully();
childGroup.shutdownGracefully();
}
}
}
服务端handler:
public class RpcServerHandler extends SimpleChannelInboundHandler<Invocation> {
private Map<String, Object> registerMap;
public RpcServerHandler(Map<String, Object> registerMap) {
this.registerMap = registerMap;
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, Invocation msg) throws Exception {
Object result = "没有指定的提供者";
if (registerMap.containsKey(msg.getClassName())) {
Object provider = registerMap.get(msg.getClassName());
result = provider.getClass()
.getMethod(msg.getMethodName(), msg.getParamTypes())
.invoke(provider, msg.getParamValues());
}
ctx.writeAndFlush(result);
ctx.close();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
3、客户端包
rpc调用者:
public class RpcConsumer {
public static void main(String[] args) {
SomeService service = RpcProxy.create(SomeService.class);
System.out.println(service.hello("java"));
System.out.println(service.hashCode());
}
}
prc代理:
public class RpcProxy {
// 泛型方法
public static <T> T create(Class<?> clazz) {
return (T) Proxy.newProxyInstance(clazz.getClassLoader(),
new Class[]{clazz},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 若调用的是Object的方法,则直接进行本地调用
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
// 进行远程调用
return rpcInvoke(clazz, method, args);
}
});
}
private static Object rpcInvoke(Class<?> clazz, Method method, Object[] args) throws InterruptedException {
RpcClientHandler handler = new RpcClientHandler();
NioEventLoopGroup loopGroup = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(loopGroup)
.channel(NioSocketChannel.class)
// Nagle算法开关,关闭Nagle算法
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// 添加编码器
pipeline.addLast(new ObjectEncoder());
// 添加解码器
pipeline.addLast(new ObjectDecoder(Integer.MAX_VALUE,
ClassResolvers.cacheDisabled(null)));
// 添加自定义处理器
pipeline.addLast(handler);
}
});
ChannelFuture future = bootstrap.connect("localhost", 8888).sync();
// 将调用信息传递给Netty Server
Invocation invocation = new Invocation();
invocation.setClassName(clazz.getName());
invocation.setMethodName(method.getName());
invocation.setParamTypes(method.getParameterTypes());
invocation.setParamValues(args);
future.channel().writeAndFlush(invocation).sync();
Object result = handler.getResult();
future.channel().closeFuture().sync();
} finally {
loopGroup.shutdownGracefully();
}
return handler.getResult();
}
}
客户端handler:
public class RpcClientHandler extends SimpleChannelInboundHandler<Object> {
private Object result;
public Object getResult() {
return this.result;
}
// msg是服务端传递来的远程调用的结果
@Override
protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
this.result = msg;
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}