简单实现的RPC

RPC,全称为Remote Procedure Call,即远程过程调用,它是一个计算机通信协议。它允许像调用本地服务一样调用远程服务。它可以有不同的实现方式。如RMI(远程方法调用)、Hessian、Http invoker等。另外,RPC是与语言无关的。

项目地址:http://download.csdn.net/detail/u013725455/9784408

简单实现的RPC_第1张图片

InvokeModel类,封装了参数类型、参数值、服务接口

/*
 * 文件名:InvokeModel.java
 * 版权:Copyright 2007-2017 517na Tech. Co. Ltd. All Rights Reserved. 
 * 描述: InvokeModel.java
 * 修改人:peiyu
 * 修改时间:2017年3月17日
 * 修改内容:新增
 */
package com.rpc.model;

import java.io.Serializable;

/**
 * 
 * @author     peiyu
 */
@SuppressWarnings("rawtypes")
public class InvokeModel implements Serializable{

    /**
     * 添加字段注释.
     */
    private static final long serialVersionUID = 1L;

    private String methodName;
    private String serviceName;
    private Object[] params;
    private Class[] paramsType;
    /**
     * 设置methodName.
     * @return 返回methodName
     */
    public String getMethodName() {
        return methodName;
    }
    /**
     * 设置serviceName.
     * @return 返回serviceName
     */
    public String getServiceName() {
        return serviceName;
    }
    /**
     * 设置params.
     * @return 返回params
     */
    public Object[] getParams() {
        return params;
    }
    /**
     * 获取methodName.
     * @param methodName 要设置的methodName
     */
    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }
    /**
     * 获取serviceName.
     * @param serviceName 要设置的serviceName
     */
    public void setServiceName(String serviceName) {
        this.serviceName = serviceName;
    }
    /**
     * 获取params.
     * @param params 要设置的params
     */
    public void setParams(Object[] params) {
        this.params = params;
    }
    /**
     * 设置paramsType.
     * @return 返回paramsType
     */
    public Class[] getParamsType() {
        return paramsType;
    }
    /**
     * 获取paramsType.
     * @param paramsType 要设置的paramsType
     */
    public void setParamsType(Class[] paramsType) {
        this.paramsType = paramsType;
    }
}

RPCClient类,客户端远程调用服务端

/*
 * 文件名:PRCClient.java
 * 版权:Copyright 2007-2017 517na Tech. Co. Ltd. All Rights Reserved. 
 * 描述: PRCClient.java
 * 修改人:peiyu
 * 修改时间:2017年3月17日
 * 修改内容:新增
 */
package com.rpc.client;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetSocketAddress;
import java.net.Socket;

import com.alibaba.fastjson.JSON;
import com.rpc.model.InvokeModel;
import com.rpc.util.CloseUtil;

/**
 * @author peiyu
 */
public class RPCClient {
    @SuppressWarnings("unchecked")
    public static  T getPRCProxy(Class clazz, final InetSocketAddress addr) {
        return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Socket socket = null;
                ObjectInputStream ois = null;
                ObjectOutputStream oos = null;
                try {
                    socket = new Socket();
                    socket.connect(addr);
                    oos = new ObjectOutputStream(socket.getOutputStream());
                    InvokeModel invokeModel = getInvokeModel(clazz, method, args);
                    oos.writeUTF(JSON.toJSONString(invokeModel));
                    oos.flush();
                    ois = new ObjectInputStream(socket.getInputStream());
                    return ois.readUTF();
                } finally {
                    CloseUtil.close(socket);
                    CloseUtil.close(oos);
                    CloseUtil.close(ois);
                }
            }
        });
    }
    private static  InvokeModel getInvokeModel(Class clazz, Method method, Object[] args) {
        InvokeModel invokeModel = new InvokeModel();
        invokeModel.setMethodName(method.getName());
        invokeModel.setParams(args);
        invokeModel.setServiceName(clazz.getName());
        invokeModel.setParamsType(method.getParameterTypes());
        return invokeModel;
    }
}

RPCServer 接口,RPC提供的接口

/*
 * 文件名:PRCServer.java
 * 版权:Copyright 2007-2017 517na Tech. Co. Ltd. All Rights Reserved. 
 * 描述: PRCServer.java
 * 修改人:peiyu
 * 修改时间:2017年3月17日
 * 修改内容:新增
 */
package com.rpc.server;

/**
 * 
 * @author     peiyu
 */
public interface RPCServer {
    public void stop();
    public void start() throws Throwable;
    public void register(Class service, Class serviceImpl);
    public int getPort();
    public boolean isRuning();
}

RPC接口实现类,监听客户端的远程请求

/*
 * 文件名:PRCServerCenter.java
 * 版权:Copyright 2007-2017 517na Tech. Co. Ltd. All Rights Reserved. 
 * 描述: PRCServerCenter.java
 * 修改人:peiyu
 * 修改时间:2017年3月17日
 * 修改内容:新增
 */
package com.rpc.server;

import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import com.rpc.util.CloseUtil;

/**
 * @author peiyu
 */
public class RPCServerCenter implements RPCServer {
    private static Map> registerCenter = new HashMap<>();
    private ExecutorService executor = Executors.newCachedThreadPool();
    private boolean isRunnig = false;
    private int port = 80;
    public RPCServerCenter(int port) {
        this.port = port;
    }
    @Override
    public void stop() {
        try {
            executor.shutdown();
        } finally {
            isRunnig = false;
        }
    }
    @Override
    public void start() throws Throwable {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket();
            serverSocket.bind(new InetSocketAddress(port));
            System.out.println("server start at listen to " + port+"。。。。。。");
            isRunnig = true;
            while (true) {
                executor.execute(new RPCServiceHandler(serverSocket.accept(), registerCenter));
            } 
        } finally {
            CloseUtil.close(serverSocket);
        }
    }
    @Override
    public void register(Class service, Class serviceImpl) {
        registerCenter.put(service.getName(), serviceImpl);
    }
    @Override
    public int getPort() {
        return this.port;
    }
    @Override
    public boolean isRuning() {
        return this.isRunnig;
    }
}

RPCServiceHandler 类,请求处理,找到调用接口,进行业务处理并返回结果

/*
 * 文件名:PRCServiceHandler.java
 * 版权:Copyright 2007-2017 517na Tech. Co. Ltd. All Rights Reserved. 
 * 描述: PRCServiceHandler.java
 * 修改人:peiyu
 * 修改时间:2017年3月17日
 * 修改内容:新增
 */
package com.rpc.server;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.Socket;
import java.util.Map;

import com.alibaba.fastjson.JSON;
import com.rpc.model.InvokeModel;
import com.rpc.util.CloseUtil;

/**
 * @author peiyu
 */
public class RPCServiceHandler implements Runnable {
    private Socket client;
    private Map> registerCenter;
    public RPCServiceHandler(Socket client, Map> registerCenter) {
        this.client = client;
        this.registerCenter = registerCenter;
    }
    public void run() {
        ObjectInputStream input = null;
        ObjectOutputStream output = null;
        try {
            //将客户端发送的码流反序列化成对象,反射调用服务实现者,获取执行结果
            input = new ObjectInputStream(client.getInputStream());
            String param =input.readUTF();
            System.out.println("请求参数:" + param);
            InvokeModel invokeModel = JSON.parseObject(param, InvokeModel.class);
            Class serviceClass = registerCenter.get(invokeModel.getServiceName());
            if (serviceClass == null) {
                throw new ClassNotFoundException(invokeModel.getServiceName() + " not found");
            }
            Method method = serviceClass.getMethod(invokeModel.getMethodName(), invokeModel.getParamsType());
            Object result = method.invoke(serviceClass.newInstance(), invokeModel.getParams());
            System.out.println("返回结果:" + JSON.toJSONString(result));
            //将执行结果反序列化,通过socket发送给客户端
            output = new ObjectOutputStream(client.getOutputStream());
            output.writeUTF(JSON.toJSONString(result));
            output.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            CloseUtil.close(output);
            CloseUtil.close(input);
            CloseUtil.close(client);
        }
    }
}

服务接口

/*
 * 文件名:ISayHello.java
 * 版权:Copyright 2007-2017 517na Tech. Co. Ltd. All Rights Reserved. 
 * 描述: ISayHello.java
 * 修改人:peiyu
 * 修改时间:2017年3月17日
 * 修改内容:新增
 */
package com.rpc.service;

/**
 * @author     peiyu
 */
public interface ISayHello {
    public String sayHello(String name);
}

接口的实现

/*
 * 文件名:SayHelloImpl.java
 * 版权:Copyright 2007-2017 517na Tech. Co. Ltd. All Rights Reserved. 
 * 描述: SayHelloImpl.java
 * 修改人:peiyu
 * 修改时间:2017年3月17日
 * 修改内容:新增
 */
package com.rpc.service;

/**
 * @author     peiyu
 */
public class SayHelloImpl implements ISayHello {
    @Override
    public String sayHello(String name) {
        System.out.println(name+" : hello world");
        return name+" : hello world";
    }
}

测试启动服务

/*
 * 文件名:Test.java
 * 版权:Copyright 2007-2017 517na Tech. Co. Ltd. All Rights Reserved. 
 * 描述: Test.java
 * 修改人:peiyu
 * 修改时间:2017年3月17日
 * 修改内容:新增
 */
package com.rpc.test;

import com.rpc.server.RPCServer;
import com.rpc.server.RPCServerCenter;
import com.rpc.service.ISayHello;
import com.rpc.service.SayHelloImpl;

/**
 * @author peiyu
 */
public class ServerTest {
    public static void main(String[] args) throws Throwable {
       RPCServer prcServer=new RPCServerCenter(8888);
       prcServer.register(ISayHello.class, SayHelloImpl.class);
       prcServer.start();
    }
}

测试客户端请求

/*
 * 文件名:Test.java
 * 版权:Copyright 2007-2017 517na Tech. Co. Ltd. All Rights Reserved. 
 * 描述: Test.java
 * 修改人:peiyu
 * 修改时间:2017年3月17日
 * 修改内容:新增
 */
package com.rpc.test;

import java.net.InetSocketAddress;

import com.rpc.client.RPCClient;
import com.rpc.service.ISayHello;

/**
 * @author peiyu
 */
public class ClientTest {
    public static void main(String[] args) {
        InetSocketAddress addr = new InetSocketAddress("localhost", 8888);
        ISayHello sayHello = RPCClient.getPRCProxy(ISayHello.class, addr);
        System.out.println("prc返回:" + sayHello.sayHello("张三"));
    }
}

结果:

【客户端】
prc返回:"张三 : hello world"
【服务端】
server start at listen to 8888
请求参数:{"methodName":"sayHello","params":["张三"],"paramsType":["java.lang.String"],"serviceName":"com.rpc.service.ISayHello"}
张三 : hello world
返回结果:"张三 : hello world"

你可能感兴趣的:(RPC框架)