基于netty的RPC框架

基于netty的RPC框架

什么是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();
            }
        });
    }
}

你可能感兴趣的:(netty)