一个小demo:RPC 远程调用

暴露服务

接口

public interface RpcService {

    String getMsg(int param1, int param2);

}

实现

public class RpcServiceImpl implements RpcService {

    @Override
    public String getMsg(int param1, int param2) {
        return param2 + " - " + param1 + " = " + (param2 - param1);
    }

}

服务

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

public class ExposureServer {

    /**
     * 服务端端口
     */
    private static final int PORT = 12345;

    public static void main(String[] args) throws Exception {
        RpcService service = new RpcServiceImpl();
        new ExposureServer().exposure(service, PORT);
    }

    /**
     * 功能描述:
     * <暴露服务>
     *
     * @param object 1 需要暴露的接口实现
     * @param port   2
     * @return void
     * @author zhoulipu
     * @date 2019/8/8 20:33
     */
    public void exposure(Object object, int port) throws Exception {
        System.out.println("暴露接口实现:" + object.getClass().getName());
        // 服务端开启
        ServerSocket server = new ServerSocket(port);
        // 循环监听客户端连接
        while (true) {
            // 等待客户端进行连接
            Socket socket = server.accept();
            // 开启新线程处理实现
            new TaskHandler (socket, object).start();
        }
    }

    /**
     * 实现监听
     */
    class TaskHandler extends Thread {

        private Socket socket;
        private Object object;

        private TaskHandler (Socket socket, Object object) {
            this.socket = socket;
            this.object = object;
        }

        @Override
        public void run() {
            try {
                try {
                    // 获取输入流
                    ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
                    try {
                        // 获取方法名、参数类型、参数(顺序与引用服务保持一致)
                        String methodName = in.readUTF();
                        Class<?>[] parameterTypes = (Class<?>[]) in.readObject();
                        Object[] arguments = (Object[]) in.readObject();
                        // 获取输出流
                        ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
                        try {
                            // 获取接口实现
                            Method method = object.getClass().getMethod(methodName, parameterTypes);
                            // 调用接口实现
                            Object result = method.invoke(object, arguments);
                            out.writeObject(result);
                        } catch (Throwable t) {
                            out.writeObject(t);
                        } finally {
                            out.close();
                        }
                    } finally {
                        in.close();
                    }
                } finally {
                    socket.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

引用服务

接口

public interface RpcService {

    String getMsg(int param1, int param2);

}

服务

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.Socket;

public class ReferenceServer {

    /**
     * 暴露服务地址
     */
    private static final String HOST = "127.0.0.1";

    /**
     * 暴露服务端口
     */
    private static final int PORT = 12345;

    public static void main(String[] args) {
        RpcService service = reference(RpcService.class, HOST, PORT);
        System.out.println(service.getMsg(1, 2));
    }

    /**
     * 功能描述:
     * <引用服务 @SuppressWarnings("unchecked") 编译器忽略动态代理警告>
     *
     * @param interfaceClass 1
     * @param host           2
     * @param port           3
     * @return T
     * @author zhoulipu
     * @date 2019/8/8 20:31
     */
    @SuppressWarnings("unchecked")
    private static <T> T reference(final Class<T> interfaceClass, final String host, final int port) {
        System.out.println("获取远程实现:" + interfaceClass.getName());
        // 动态代理获取实现(类加载器加载代理对象,需要实现的接口,调用管理者)
        return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class<?>[]{interfaceClass}, new InvocationHandler() {
            // 代理类(代理对象,调用的方法,方法的参数)
            public Object invoke(Object proxy, Method method, Object[] arguments) throws Throwable {
                // 创建连接
                Socket socket = new Socket(host, port);
                try {
                    // 获取输出流
                    ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
                    try {
                        // 写入(方法名(UTF格式),参数类型,参数)(顺序与暴露服务保持一致)
                        out.writeUTF(method.getName());
                        out.writeObject(method.getParameterTypes());
                        out.writeObject(arguments);
                        // 获取输入流
                        ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
                        try {
                            Object result = in.readObject();
                            // 判断输入对象是否抛出异常(instanceof:判断一个对象是否为一个类的实例)
                            if (result instanceof Throwable) {
                                throw (Throwable) result;
                            }
                            return result;
                        } finally {
                            in.close();
                        }
                    } finally {
                        out.close();
                    }
                } finally {
                    socket.close();
                }
            }
        });
    }

}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值