使用Socket,动态代理,反射实现简单的RPC远程调用

新建三个model
服务提供方:rpc-consume
服务消费方:rpc-provide
提供远程调用:rpc-framework


服务提供方:rpc-consume代码
pom.xml:

<dependencies>
        <dependency>
            <groupId>demo</groupId>
            <artifactId>framework</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

ProvideApplication类(用于暴露服务):

 package com.provide.demo;

import com.framework.demo.RpcFramework;
import com.provide.demo.impl.UserServiceImpl;

public class ProvideApplication {

    public static void main(String[] args) {
        UserService userService = new UserServiceImpl() ;
        //将服务暴露,供客户端消费
        RpcFramework.export(userService, 8111);
    }
}

UserService:

package com.provide.demo;

public interface UserService {

    String sayHelloWordMethod(String parameter);
}

UserServiceImpl:

   package com.provide.demo.impl;

import com.provide.demo.UserService;

public class UserServiceImpl implements UserService {

    public String sayHelloWordMethod(String parameter) {
        System.out.println(parameter);
        return "hello 我是:Provide";
    }
}

服务消费方:rpc-provide代码
pom.xml:

 <dependencies>
        <dependency>
            <groupId>demo</groupId>
            <artifactId>framework</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

ConsumerApplication类(用于获取代理对象,执行方法):

 package com.provide.demo;

import com.framework.demo.RpcFramework;

public class ConsumerApplication {

    public static void main(String[] args) {

        UserService userService = RpcFramework.refer(UserService.class, "127.0.0.1", 8111);
        String hello = userService.sayHelloWordMethod("hello 我是:Consumer");
        System.out.println(hello);
    }
}

UserService接口:

package com.provide.demo;

public interface UserService {

    String sayHelloWordMethod(String parameter) ;
}

提供远程调用:rpc-framework代码
RpcFramework(核心类):

package com.framework.demo;

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.ServerSocket;
import java.net.Socket;

public class RpcFramework {
//获取代理对象
    public static <T> T refer(final Class<T> interfaceClass, final String host, final int port) {
        /**
         * JDK提供的动态代理,要求被代理的类必须实现一个接口
         *
         */
        //返回代理对象
        return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{interfaceClass}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //创建Socket客户端对象,绑定服务端的ip和端口
                Socket socket = new Socket(host, port);
                //构造序列化流,用于向服务端写入
                ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                //方法名
                //writeUTF(String str):写出一个UTF-8编码的字符串
                oos.writeUTF(method.getName());
                //方法形参类型
                //writeObject(Object obj)写入一个对象
                oos.writeObject(method.getParameterTypes());
                //方法参数
                oos.writeObject(args);

                //反序列化流,用于接收服务端的返回值
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                //读取
                Object obj = ois.readObject();
                return obj;
            }
        });
    }

    /**
     * 将服务暴露,供消费放方调用
     *
     * @param obj
     * @param port
     */
    public static void export(final Object obj, final int port) {

        try {
            //创建ServerSocket服务端对象,向系统指定端口
            ServerSocket serverSocket = new ServerSocket(port);

            //轮询
            while (true) {
                final Socket accept = serverSocket.accept();
                //开启多线程,处理消息,返回结果
                new Thread(() -> {
                    try {
                        /**
                         * 注意:
                         * 使用序列化对象时的顺序
                         * 服务端先建立ObjectInputStream后建立ObjectOutputStream
                         * 则对应地客户端要先建立ObjectOutputStream后建立ObjectInputStream
                         * 否则会造成两方互相等待数据而导致死锁。
                         *
                         * 原因是建立ObjectInputStream对象是需要先接收一定的header数据
                         * 接收到这些数据之前会处于阻塞状态。
                         */
                        //反序列化对象
                        ObjectInputStream ois = new ObjectInputStream(accept.getInputStream());
                        //方法名
                        String methodName = ois.readUTF();
                        //形参类型
                        Class<?>[] paramsTypes = (Class<?>[]) ois.readObject();
                        //方法参数
                        Object[] args = (Object[]) ois.readObject();

                        //使用反射,获得方法对象
                        Method method = obj.getClass().getMethod(methodName, paramsTypes);
                        Object invoke = method.invoke(obj, args);

                        //将方法的返回值写会客户端
                        ObjectOutputStream oos = new ObjectOutputStream(accept.getOutputStream());
                        oos.writeObject(invoke);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                ).start();

            }


        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

测试,先启动提供方,再启动消费方

提供方打印结果:
在这里插入图片描述
消费方打印结果:
在这里插入图片描述
ok,以上。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值