什么是rpc
rpc是远程过程调用的简称,它可以通过网络调用另一台服务器的某个方法
技术点
网络编程,反射,协议
代码
pom
<dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> <version>3.8.0</version> </dependency> <!-- https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java-util --> <dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java-util</artifactId> <version>3.8.0</version> </dependency> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.25.Final</version> </dependency> <!-- <dependency>--> <!-- <groupId>com.googlecode.protobuf-java-format</groupId>--> <!-- <artifactId>protobuf-java-format</artifactId>--> <!-- <version>1.2</version>--> <!-- </dependency>--> <dependency> <groupId>org.reflections</groupId> <artifactId>reflections</artifactId> <version>0.9.10</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.1.26</version> <type>jar</type> <scope>compile</scope> </dependency> <!-- marshalling --> <dependency> <groupId>org.jboss.marshalling</groupId> <artifactId>jboss-marshalling-serial</artifactId> <!-- <version>2.0.0.Final</version> --> <!-- 需要JDK1.8支持 --> <version>1.4.11.Final</version> <!-- 需要JDK1.7支持 --> </dependency> <dependency> <groupId>org.jboss.marshalling</groupId> <artifactId>jboss-marshalling</artifactId> <version>1.4.11.Final</version> </dependency> <!-- log4j start --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!-- log4j end --> <!-- slf4j bound to Log4j start --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.6</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.6</version> </dependency> <!-- slf4j bound to Log4j end --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>net.coobird</groupId> <artifactId>thumbnailator</artifactId> <version>0.4.8</version> </dependency> <dependency> <groupId>io.lettuce</groupId> <artifactId>lettuce-core</artifactId> <version>5.1.3.RELEASE</version> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.10.0-m1</version> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>RELEASE</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>RELEASE</version> <scope>compile</scope> </dependency>
entity包
public class ClassInfo implements Serializable { //类全路径名,方法名,参数类型数组,参数数组 private String className; private String methodName; private Class[] paramsTypeArr; private Object[] paramsArr; 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[] getParamsTypeArr() { return paramsTypeArr; } public void setParamsTypeArr(Class[] paramsTypeArr) { this.paramsTypeArr = paramsTypeArr; } public Object[] getParamsArr() { return paramsArr; } public void setParamsArr(Object[] paramsArr) { this.paramsArr = paramsArr; } }
public class User implements Serializable{ private int id; private String name; private int age; public User(){ } public User(int id,String name,int age){ this.id=id; this.name=name; this.age=age; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } }
server
public interface UserService { User getUser(int id); }
public class UserServiceImpl implements UserService{ List<User> userList = new ArrayList<>(); { for(int i=0;i<10;i++){ User user = new User(i,"name"+i,20+i); userList.add(user); } } @Override public User getUser(int id) { return userList.get(id); } }
public class ServerMain { public static void main(String[] args) { EventLoopGroup boss = new NioEventLoopGroup(1); EventLoopGroup worker = new NioEventLoopGroup(); ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(boss,worker); serverBootstrap.channel(NioServerSocketChannel.class); serverBootstrap.option(ChannelOption.SO_BACKLOG,128); //设置线程队列中等待连接的个数 serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE,true);//保持活动连接状态 serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new ObjectEncoder()); pipeline.addLast(new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null))); pipeline.addLast(new ServerHandler()); } }); try{ ChannelFuture future = serverBootstrap.bind(9999).sync();//设置端口 非阻塞 System.out.println(".........server start.........."); future.channel().closeFuture().sync(); }catch (InterruptedException e){ e.printStackTrace(); }finally { boss.shutdownGracefully(); worker.shutdownGracefully(); } } }
public class ServerHandler extends ChannelInboundHandlerAdapter { private static ExecutorService executorService= Executors.newFixedThreadPool(1000); @Override public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception { executorService.submit(new Runnable() { @Override public void run() { try { ClassInfo classInfo= (ClassInfo) msg; Object o = Class.forName(getImplClassName(classInfo)).newInstance(); Method method = o.getClass().getMethod(classInfo.getMethodName(), classInfo.getParamsTypeArr()); Object invoke = method.invoke(o, classInfo.getParamsArr()); ctx.channel().writeAndFlush(invoke); }catch (Exception e){ e.printStackTrace(); } } }); } //得到某个接口下的实现类 public String getImplClassName(ClassInfo classInfo) throws Exception { //服务器接口与实现类地址; 这个路径是server包接口UserService所在路径 String iName="com.lry.basic.netty.demo4.server"; int i = classInfo.getClassName().lastIndexOf("."); String className=classInfo.getClassName().substring(i); Class aClass = Class.forName(iName + className); Reflections reflections=new Reflections(iName); Set<Class<?>> classes=reflections.getSubTypesOf(aClass); if(classes.size()==0){ System.out.println("未找到实现类"); return null; }else if(classes.size()>1){ System.out.println("找到多个实现类,未明确使用哪个实现类"); return null; }else{ Class[] classes1 = classes.toArray(new Class[0]); return classes1[0].getName(); } } }
client
public interface UserService { User getUser(int id); }
public class ClientMain { public static void main(String[] args) { UserService userService = (UserService) RpcProxy.remoteCall(UserService.class); System.out.println(userService.getUser(1)); } }
public class ClientHandler extends ChannelInboundHandlerAdapter { private Object response; public Object getResponse() { return response; } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { response = msg; ctx.close(); } }
public class RpcProxy { public static Object remoteCall(final Class clazz){ return Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //组装ClassInfo发送给服务器 ClassInfo classInfo = new ClassInfo(); classInfo.setClassName(clazz.getName()); classInfo.setMethodName(method.getName()); classInfo.setParamsTypeArr(method.getParameterTypes()); classInfo.setParamsArr(args); EventLoopGroup group = new NioEventLoopGroup(); final ClientHandler clientHandler = new ClientHandler(); try{ Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group); bootstrap.channel(NioSocketChannel.class); bootstrap.handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new ObjectEncoder()); pipeline.addLast(new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null))); pipeline.addLast(clientHandler); } }); ChannelFuture future = bootstrap.connect(new InetSocketAddress("localhost",9999)).sync(); future.channel().writeAndFlush(classInfo).sync(); future.channel().closeFuture().sync(); }finally { group.shutdownGracefully(); } return clientHandler.getResponse(); } }); } }