socket实现RPC

 

来源这位大佬https://blog.csdn.net/u013374645/article/details/82083414  ,  学习之 ,  模仿之 , 稳

Rpc是远程调用服务 , 通过Socket来实现时 , 服务是注册在服务端 , 客户端连上服务端实现调用对应服务

创建Service服务

服务接口

public interface ExecCommand {
    String exec(String command,int num);
}

服务实现类

import xuyingwx.rpc.service.ExecCommand;

public class ExecCommandImpl implements ExecCommand{
    @Override
    public String exec(String command,int num) {
        System.out.println(String.format("执行:", command));
        System.out.println("-------------------------------");
        return String.format("执行:%s  完毕", command);
    }
}

创建服务端server

server接口

public interface Server {
    void stop();//关闭服务端
    void start() throws Exception;//启动服务端
    void register(Class serviceInterface , Class impl);//注册服务
    boolean isRunning();
    int port();
}

server实现 , 服务端是有具体的服务实现类

public class ServerImpl implements Server{
    //创建线程池
    private static ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
    //服务注册
    private static final HashMap<String,Class> serviceRegistry = new HashMap<>();
    
    private static boolean running = false;
    
    private static int port;
    
    public ServerImpl(int port) {
        super();
        this.port = port;
    }

    @Override
    public void stop() {
        // TODO Auto-generated method stub
        running = false;
        executor.shutdown();
    }

    @Override
    public void start() throws Exception {
        ServerSocket serverSocker = new ServerSocket();
        serverSocker.bind(new InetSocketAddress(port));
        System.out.println("start server");
        try {
            while (true) {
                //启动服务端:线程池启动服务端线程,socket等待调用
                executor.execute(new ServerThread(serverSocker.accept()));
                System.out.println("此次循环结束");
            }
        } finally {
            serverSocker.close();
        }
    }

    @Override
    public void register(Class serviceInterface, Class impl) {
        serviceRegistry.put(serviceInterface.getName(), impl);//注册服务
    }

    @Override
    public boolean isRunning() {
        return this.running;
    }

    @Override
    public int port() {
        return this.port;
    }
    
    public class ServerThread implements Runnable {
        private Socket socket;

        public ServerThread(Socket accept) {
            this.socket = accept;
        }

        @Override
        public void run() {
            ObjectInputStream input = null;
            ObjectOutputStream output = null;
            try {
                input = new ObjectInputStream(socket.getInputStream());
                //1需要和客户端输出的顺序一样
                String serviceName = input.readUTF();
                String methodName = input.readUTF();
                Class<?>[] parameterTypes = (Class<?>[]) input.readObject();
                Object[] arguments = (Object[]) input.readObject();
                //2根据serviceName获取服务实现class , 然后再通过反射 , 调用对应的method , 实现调用服务功能
                Class serviceClass = serviceRegistry.get(serviceName);
                if (serviceClass == null) {
                    throw new ClassNotFoundException(serviceName + " not found");
                }
                Method method = serviceClass.getMethod(methodName, parameterTypes);
                Object result = method.invoke(serviceClass.newInstance(), arguments);
                //3将服务调用结果返回给客户端
                output = new ObjectOutputStream(socket.getOutputStream());
                output.writeObject(result);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                IOUtils.closeQuietly(input);
                IOUtils.closeQuietly(output);
                IOUtils.closeQuietly(socket);
            }
        }

    }

}

创建客户端Client

        客户端讲道理,是有依赖到服务的接口类 , 所以知道到想要调用哪个类哪个方法 , 所以每次要调用的时候 , 可以创建socket客户端连上服务端 , 把要调用的服务的信息传到服务端 , 服务端通过反射执行 .

        每次调用都要创建socket连上服务端 , 我们有interface , 所以可以通过jdk动态代理来实现 , 然后就是每次创建一个代理对象去调用

jdk动态代理handler , 用于返回代理对象 , invoke就是去创建socket客户端请求服务端

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 org.apache.commons.io.IOUtils;

public class JdkInvocationHandler implements InvocationHandler{
    private Class targetClass;
    private InetSocketAddress addr;
    
    public JdkInvocationHandler(Class targetClass,InetSocketAddress addr){
        this.targetClass = targetClass;
        this.addr = addr;
    }
    
    public Object newProxy(){  
        //返回一个代理对象  
        return Proxy.newProxyInstance(
            this.targetClass.getClassLoader(),   
            new Class<?>[]{this.targetClass},   
            this);  
    } 
      
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //通过socket连上服务端去执行对应的方法
        Socket socket = null;
        socket = new Socket();
        socket.connect(addr);
        ObjectOutputStream oos = null;
        ObjectInputStream ois = null;
        try {
            oos = new ObjectOutputStream(socket.getOutputStream());
            oos.writeUTF(targetClass.getName());//classname
            oos.writeUTF(method.getName());
            oos.writeObject(method.getParameterTypes());
            oos.writeObject(args);
            ois = new ObjectInputStream(socket.getInputStream());//等待获取socket返回
            return ois.readObject();//返回代理对象
        } finally {
            IOUtils.closeQuietly(socket);
            IOUtils.closeQuietly(oos);
            IOUtils.closeQuietly(ois);
        }
        
    }

}

ServiceJdkProxy封装动态代理功能 , 返回JdkInvocationHandler创建的代理对象

import java.net.InetSocketAddress;

public class ServiceJdkProxy{
    public static Object  getProxyInstance(Class targetClass, final InetSocketAddress addr) {
        JdkInvocationHandler jdkInvocationHandler = new JdkInvocationHandler(targetClass,addr);
        Object newProxy = jdkInvocationHandler.newProxy();
        return newProxy;
    }
}

最后是服务提供方和消费方

ProviderRun

import xuyingwx.rpc.service.ExecCommand;
import xuyingwx.rpc.service.impl.ExecCommandImpl;
import xuyingwx.rpc.socket.server.impl.ServerImpl;

public class ProviderRun {
    public static void main(String[] args) {
        //简单创建一个线程创建服务端 , 并注册一个服务
        new Thread(new Runnable() {
            public void run() {
                try {
                    Server serviceServer = new ServerImpl(8123);
                    serviceServer.register(ExecCommand.class, ExecCommandImpl.class);
                    serviceServer.start();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

ConsumerRun

import java.net.InetSocketAddress;

import xuyingwx.rpc.service.ExecCommand;
import xuyingwx.rpc.socket.client.util.ServiceJdkProxy;

public class ConsumerRun {
    /**
     * 客户端调用服务 , 使用动态代理 , 调用服务时 , 是通过socket连上服务端去执行对应的方法 , 从而实现rpc调用
     */
    public static void main(String[] args) {
        ExecCommand proxyInstance = (ExecCommand) ServiceJdkProxy.getProxyInstance(ExecCommand.class,new InetSocketAddress(8123));
        String exec = proxyInstance.exec("asd",123);
        System.out.println(exec);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值