【分布式远程通信】

一、网络通信Socket

  • 服务端 ServerSocket
public class ServerSocketDemo {

    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(8080);
            Socket socket = serverSocket.accept();//监听客户端连接
            System.out.println("=====Port Number: ====="+socket.getPort());
            //读
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));//输入流
            String clientStrInfo = bufferedReader.readLine();//读取客户端的一行数据
            System.out.println("=====The Client message was received: =====\n"+clientStrInfo);

            //写
            BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            bufferedWriter.write("=====I got the message:=====\n");//以换行符说明服务端已发送完成,客户端不再监听
            bufferedWriter.flush();

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭
//            socket.close();
        }
    }
}
  • 客户端Socket
public class SocketClientDemo {
    public static void main(String[] args) {
        Socket socket = null;
        try {
            socket = new Socket("localhost", 8080);
            //写
            BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            bufferedWriter.write("=====I'm the client and I've sent a message.=====\n");
            bufferedWriter.flush();

            //读
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String serverInfo = bufferedReader.readLine();
            System.out.println("===== server return info :=====\n"+serverInfo);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

1.1 OSI模型

OSI负载均衡依据各层解释
应用层URL为应用程序提供服务
表示层数据格式转换、数据加密
会话层建立、管理和维护会话
传输层TCP/IP :端口号建立、管理和维护到端的连接
网络层IPIP选址及路由选择
数据链路层MAP提供介质访问和链路管理
物理层物理层

1.2 三挥四握

二、阻塞和非阻塞机制

2.1 阻塞IO(BIO)

  • 连接阻塞
  • IO阻塞
    • IO阻塞优化(使用异步线程)
    • serverSocketDemo.java
		private static final ExecutorService executorService = Executors.newFixedThreadPool(20);

    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(8080);
            while (true) {
                Socket socket = serverSocket.accept();//监听客户端连接(连接阻塞)
                System.out.println("=====Port Number: =====" + socket.getPort());
                executorService.execute(new SocketThread(socket));//4.传Socket-->异步线程池处理IO
            }
  • SocketThread.java
//1.实现Runnable接口。
public class SocketThread implements Runnable{
    private final Socket socket;
	//3.把Socket传进来
    public SocketThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
		//2.IO操作写在线程体
        BufferedReader bufferedReader = null;//输入流
        try {
            //读
            bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String clientStrInfo = bufferedReader.readLine();//读取客户端的一行数据
            System.out.println("=====The Client message was received: =====\n"+clientStrInfo);

            //写
            BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            bufferedWriter.write("=====I got the message:=====\n");//以换行符说明服务端已发送完成,客户端不再监听
            bufferedWriter.flush();

            bufferedWriter.close();
            bufferedReader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

2.2 非阻塞IO(NIO)(New IO)非阻塞模型(No-Blocked IO)

  • 连接阻塞 =》连接非阻塞
  • IO阻塞 =》IO非阻塞

NewIOServer.java

public class NewIOServer {
    //非阻塞IO ServerSocketChannel//Channel Buffer Selector
    public static void main(String[] args) {
        try {
            ServerSocketChannel  severSocketChannel = ServerSocketChannel.open();
            severSocketChannel.configureBlocking(false);//配置非阻塞(默认阻塞)
            severSocketChannel.socket().bind(new InetSocketAddress(8080));

            while (true){
                SocketChannel socketChannel = severSocketChannel.accept();
                if (socketChannel!=null){
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);//分配缓冲区
                    socketChannel.read(byteBuffer);//数据读到缓冲区
                    System.out.println("=====Server receive info:"+new String(byteBuffer.array()));
                    byteBuffer.flip();//翻转
                    socketChannel.write(byteBuffer);//写出
                }else {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("=====连接未就绪=====");
                }
            }

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

NewIOSocketClientDemo.java

public class NewIOSocketClientDemo {

    public static void main(String[] args) {
        try {
            SocketChannel socketChannel = SocketChannel.open();
            socketChannel.connect(new InetSocketAddress("localhost",8080));
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            byteBuffer.put("======我是SocketChannel客户端".getBytes());
            byteBuffer.flip();//翻转
            socketChannel.write(byteBuffer);

            //读取数据
            byteBuffer.clear();
            int count = socketChannel.read(byteBuffer);
            if ( count> 0) {
                System.out.println("=====收到服务端数据====="+new String(byteBuffer.array()));
            }else System.out.println("=====没收到数据");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.2.1多路复用

  • 多路复用器 Selector
    NewIoSelectorServer.java
public class NewIoSelectorServer {
    static Selector selector;
    public static void main(String[] args) {
        try {
            selector = Selector.open();//1.多路复用器
            ServerSocketChannel  severSocketChannel = ServerSocketChannel.open();
            severSocketChannel.configureBlocking(false);//配置非阻塞(默认阻塞)
            severSocketChannel.socket().bind(new InetSocketAddress(8080));
            severSocketChannel.register(selector, SelectionKey.OP_ACCEPT);//2.注册连接事件
            while (true) {
                selector.select();//选择阻塞机制
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                if (iterator.hasNext()) {
                    SelectionKey selectionKey = iterator.next();
                    iterator.remove();//移除,防止重复key处理
                    if (selectionKey.isAcceptable()) {//事件监听
                        handleAccept(selectionKey);//2.接收连接处理
                    }else if (selectionKey.isReadable()){//事件监听
                        handleRead(selectionKey);//缓冲区读入
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void handleAccept(SelectionKey selectionKey) throws IOException {
        ServerSocketChannel serverSocketChannel =(ServerSocketChannel) selectionKey.channel();
        SocketChannel socketChannel = serverSocketChannel.accept();//接受到此通道的套接字的连接。
        socketChannel.configureBlocking(false);//非阻塞
        socketChannel.write(ByteBuffer.wrap("=====我是服务器,给你发信息".getBytes()));
        socketChannel.register(selector,SelectionKey.OP_READ);//注册读入事件
    }
    private static void handleRead(SelectionKey selectionKey) throws IOException {
        SocketChannel socketChannel =(SocketChannel) selectionKey.channel();
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        socketChannel.read(byteBuffer);
        System.out.println("=====服务器收到信息=====:"+ new String(byteBuffer.array()));
    }
}

二、序列化与反序列化

2.1 序列化与反序列化

  • 序列化 obj ->stream
  • 反序列化 stream -> obj
  • 选型
    • 压缩比
    • 夸语言

2.2Java实现

  • implements Serializable
  • ObjectInputStream ,对象输入流
  • ObjectOutputStream, 对象输出流
  • private static final long serialVersionUID = -214124124121221L;
  • WriteObject/ReadObject
  • transient

JAVASerializerImpl.java

  • ObijcetXXXStream
public class JAVASerializerImpl implements ISerializer {
    //obj->stream
    @Override
    public <T> byte[] serializer(T Object) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = null;
        try {
            objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(Object);
            System.out.println("====序列化");
            return byteArrayOutputStream.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //关流
//            byteArrayOutputStream.close();
//            objectOutputStream.close();
        }
        return null;
    }
    //stream->obj
    @Override
    public <T> T deserializer(byte[] data) {
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data);
        ObjectInputStream objectInputStream = null;
        try {
            objectInputStream = new ObjectInputStream(byteArrayInputStream);
            System.out.println("====反序列化");
            return (T)objectInputStream.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e){
            e.printStackTrace();
        }finally {
//            byteInputStream.close();
//            objectInputStream.close();
        }
        return null;
    }
}
  • SeralizerMain.java
public class SeralizerMain {
    public static void main(String[] args) {
        ISerializer javaSerializer = new JAVASerializerImpl();
        User user = new User();
        user.setName("name");
        user.setAge(10);
        byte[] bytes = javaSerializer.serializer(user);
        for (byte bt : bytes) {
            System.out.print(bt + " ");
        }//-84 -19 0 5 115 114 0 36 11
        System.out.println();
        user = javaSerializer.deserializer(bytes);
        System.out.println(user);//User{name='我的名字'}
    }
}

User.java

//实现Serializable接口=》序列化对象
public class User implements Serializable {
private static final long serialVersionUID = -21412412411221L;
    private String name;
    //transient不序列化
    private transient int age;


    //transient不直接传过去,先还要对其进行处理,用writeObject/readObject
    private void writeObject(ObjectOutputStream out) throws IOException {
        System.out.println("=====反射调用writeObject");
        out.defaultWriteObject();
        out.writeInt(age);
    }

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        System.out.println("=====反射调用readObject");
        in.defaultReadObject();
        age = in.readInt();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age='" + age + '\'' +
                '}';
    }
}

输出

=====反射调用writeObject
====序列化
-84 -19 0 5 115 114 0 36 116 111 112 46 104 121 103 121 120 120 46 100 101 109 111 46 97 99 116 83 101 114 105 97 108 105 122 97 98 108 101 46 85 115 101 114 -1 -1 -20 -122 -120 -61 -78 -85 3 0 1 76 0 4 110 97 109 101 116 0 18 76 106 97 118 97 47 108 97 110 103 47 83 116 114 105 110 103 59 120 112 116 0 4 110 97 109 101 119 4 0 0 0 10 120 
====反序列化
=====反射调用readObject
User{name='name', age='10'}

2.3 分布式架构下的序列化技术

  • 序列化数据大小、影响传输效率。
  • 跨语言-》json 、xml

2.3.1 服务与服务之间的通信

  • hassian
  • msgpack
  • protobuf(压缩率高)
  • dubbo-》hassian2
  • kyro
  • avro
  • jute(zookeeper)
  • xml
  • json跨语言、序列化效率高

2.3.2 JSON

  • Fastjson
  • Jackson(spring mvc) 性能高
  • Gson

2.3.3 Hessian

  • 性能、易用性比默认好
  • 序列化报文规则
  • dubbo hessian

HessianSerializer.java

public class HessianSerializer implements ISerializer{
    @Override
    public <T> byte[] serializer(T Object) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        HessianOutput hessianOutput = new HessianOutput(byteArrayOutputStream);
        try {
            hessianOutput.writeObject(Object);
            System.out.println("=====Hessian序列化");
            return byteArrayOutputStream.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
//            byteArrayOutputStream.close();
//            hessianOutput.close();
        }
        return new byte[0];
    }

    @Override
    public <T> T deserializer(byte[] data) {
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data);
        HessianInput hessianInput = new HessianInput(byteArrayInputStream);
        try {
            System.out.println("=====反序列化");
            return (T)hessianInput.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
//            byteArrayInputStream.close();
//            hessianInput.close();
        }
        return null;
    }
}

SeralizerMain .java

public class SeralizerMain {
    public static void main(String[] args) {
//        javaSeralizer();
        hessianSeralizer();
    }
    public static void hessianSeralizer(){
        ISerializer javaSerializer = new HessianSerializer();
        User user = new User();
        user.setName("name");
        user.setAge(10);
        byte[] bytes = javaSerializer.serializer(user);
        System.out.println("=====长度"+bytes.length);
        for (byte bt : bytes) {
            System.out.print(bt + " ");
        }//-84 -19 0 5 115 114 0 36 11
        System.out.println();
        user = javaSerializer.deserializer(bytes);
        System.out.println(user);//User{name='我的名字'}
    }
}

输出

=====Hessian序列化
=====长度55
77 116 0 36 116 111 112 46 104 121 103 121 120 120 46 100 101 109 111 46 97 99 116 83 101 114 105 97 108 105 122 97 98 108 101 46 85 115 101 114 83 0 4 110 97 109 101 83 0 4 110 97 109 101 122 
=====反序列化
User{name='name', age='0'}

2.3.4 Protobuf

  • 数据压缩(varint 算法)
    • 编码、解码 =》使用位运算
    • 压缩数据小(varint , zigzag(负数)算法)
  • TAG的计算
  • T-L-V(Tag - Length - Value)存储
  • 使用
    • 使用工具生成类 在这里插入图片描述
//protobuf生成类
public final class UserOuterClass {
public class SeralizerMain {
    public static void main(String[] args) {
        protobufSeralizer();
    }

    public static void protobufSeralizer(){
        UserOuterClass.User user = UserOuterClass.User.newBuilder().setName("mix").setAge(18).build();
        byte[] bytes = user.toByteArray();
        System.out.println("=====压缩后长度:"+bytes.length);
        for (byte by :bytes){
            System.out.print(by+" ");
        }
        System.out.println();
        UserOuterClass.User user1 = null;
        try {
            user1 = UserOuterClass.User.parseFrom(bytes);
        } catch (InvalidProtocolBufferException e) {
            e.printStackTrace();
        }
        System.out.println(user1);
    }
  }

输出

=====压缩后长度:7
10 3 109 105 120 16 18 
name: "mix"
age: 18

2.4.5 BitMap(布隆过滤器)


三 、简单RPC实现

在这里插入图片描述
Feign -伪代理

  • Webservice
  • Dubbo
  • Thrift
  • Grpc

3.1 实现

3.1.1客户端

  • 服务消费 Main.java
public class Main {

    public static void main(String[] args) {
        generalAct();
    }
    static void generalAct() {
        RpcProxyClient rpcProxyClient = new RpcProxyClient();
        //动态代理调用
        IOrderService orderService = rpcProxyClient.clientProxy(IOrderService.class, "localhost", 8080);
        System.out.println("=====拿到执行结果:" + orderService.selectOrderList());
        System.out.println("=====拿到执行结果:" + orderService.orderById("id"));
    }
}
  • 动态代理 RpcProxyClient .java
public class RpcProxyClient {

    public <T> T clientProxy(final Class<T> interfaceCls, final String host, final int port) {
        System.out.println("=====动态代理执行:"+interfaceCls.toString());
        return (T) Proxy.newProxyInstance(interfaceCls.getClassLoader(), new Class[]{interfaceCls}, new RemoteInvocationHandler(host,port));
    }
  • 实现InvocationHandler 接口动态代理。RemoteInvocationHandler .java
//实现 InvocationHandler动态代理
public class RemoteInvocationHandler implements InvocationHandler {
    private String host;
    private int port;


    public RemoteInvocationHandler(String host, int port) {
        this.host = host;
        this.port = port;
    }

    public RemoteInvocationHandler() {
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //建立远程连接
        RpcNetTransport rpcNetTransport = new RpcNetTransport(host, port);
//        Socket socket = rpcNetTransport.newSocket();
        System.out.println("====客户端建立远程连接");
//        传数据
        RpcRequest rpcRequest = new RpcRequest();
        rpcRequest.setClassName(method.getDeclaringClass().getName());//类名
        rpcRequest.setMethodName(method.getName());//方法名
        rpcRequest.setArgs(args);//参数
        rpcRequest.setTypes(method.getParameterTypes());//参数类型
        return rpcNetTransport.send(rpcRequest);//发送请求,拿到响应结果

    }
}
  • RpcNetTransport RPC连接通道
  • 序列化请求消息
  • 反序列化响应消息
//RPC连接通道
public class RpcNetTransport {
    private String host;
    private int port;

    public RpcNetTransport(String host, int port) {
        this.host = host;
        this.port = port;
    }

    public Socket newSocket(){
        Socket socket = null;
        try {
            socket = new Socket(host, port);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return socket;
    }

    //发送
   public Object send(RpcRequest request){
        Socket socket = newSocket();
       System.out.println("=====发送:"+socket.toString());
       //IO操作
        ObjectInputStream objectInputStream = null;
        ObjectOutputStream objectOutputStream = null;
        try {
            objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            objectOutputStream.writeObject(request);//序列化
            System.out.println("=====序列化");
            objectOutputStream.flush();
            System.out.println("=====反序列化");
            objectInputStream = new ObjectInputStream(socket.getInputStream());
            Object object = objectInputStream.readObject();
            System.out.println("=====服务端返回结果:"+object);
            return object;//响应结果返回
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }finally {
//            objectOutputStream.close();
        }
        return socket;
    }
}

3.1.2 服务端

  • 请求数据类 RpcRequest .java
@Data
public class RpcRequest implements Serializable {
    private static final long serialVersionUID = -5048601468056147899L;

    private String className;
    private String methodName;
    private Object[] args;
    private Class[] types;
    }

服务发布 BootStrap.java

public class BootStrap {
    public static void main(String[] args) {
      generalAct();
    }
    static void generalAct() {
        OrderServiceImpl orderService = new OrderServiceImpl();
        RpcProxyServer rpcProxyServer = new RpcProxyServer();
        rpcProxyServer.publisher(orderService, 8080);//发布
    }

}
  • 代理发布,收到请求交给executorService线程池处理。RpcProxyServer.java
public class RpcProxyServer {
    private final ExecutorService executorService = Executors.newCachedThreadPool();
    public void publisher(Object service, int port) {
        System.out.println("=====开始监听"+service.toString()+"=====端口:"+port);
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(port);
            while (true){
                Socket socket = serverSocket.accept();//监听请求
                System.out.println("=====收到请求"+socket);
                executorService.execute(new ProcessorHandler(socket,service));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • 拿到请求反射调用invoke()执行目标方法返回结果。ProcessorHandler.java
public class ProcessorHandler implements Runnable {
    private Socket socket;

    private Object service;

    public ProcessorHandler(Socket socket, Object service) {
        this.socket = socket;
        this.service = service;
    }

    @Override
    public void run() {
        //IO操作
        ObjectInputStream objectInputStream = null;
        ObjectOutputStream objectOutputStream = null;
        try {
            System.out.println("=====拿到客户端数据,反序列化");
            objectInputStream = new ObjectInputStream(socket.getInputStream());
            RpcRequest rpcRequest =(RpcRequest) objectInputStream.readObject();//反序列化

            Object invoke = invoke(rpcRequest);//反射调用
            System.out.println("=====服务端收到客户端请求处理后:"+invoke);

            System.out.println("=====发送给客户端数据,序列化");
            objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            objectOutputStream.writeObject(invoke);//返回给客户端
            objectOutputStream.flush();
        } catch (IOException | ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
            e.printStackTrace();
        }finally {
//            objectInputStream.close();
        }

    }
//动态代理 反射执行
    private Object invoke(RpcRequest rpcRequest) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Class<?> clazz = Class.forName(rpcRequest.getClassName());
        Method method = clazz.getMethod(rpcRequest.getMethodName(), rpcRequest.getTypes());
        System.out.println("====动态代理 反射执行====类名:"+clazz.getName()+"====方法:"+method.getName()+"=====参数"+rpcRequest.getArgs().toString());
        return method.invoke(service, rpcRequest.getArgs());
    }
}

3.2注解实现

借助spring容器处理机制

3.2.1 服务端

  • 注解类 RemoteService.java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)//运行时用
@Component
public @interface RemoteService {
}
  • 存储bean和method类 BeanMethod.java
public class BeanMethod {
    private Object bean;
    private Method method;
}
  • 存储发布服务实例的map
  • processor(RpcRequest rpcRequest)拿到请求数据,根据key拿到服务实例反射调用执行服务方法。
public class Mediator {

    private volatile static Mediator instance;
    //存储发布的服务实例
    public  static Map<String,BeanMethod> map = new ConcurrentHashMap<>();

    private Mediator(){};

    public static Mediator getInstance(){
        if (instance==null){
            synchronized(Mediator.class){
                if (instance==null){
                    instance = new Mediator();
                }
            }
        }
        return instance;
    }
//传入请求数据,动态代理执行方法
    public Object processor(RpcRequest rpcRequest){
        String key = rpcRequest.getClassName() + "." + rpcRequest.getMethodName();//key
        BeanMethod beanMethod = map.get(key);//得到服务能调用的方法
        if (beanMethod==null){
            return null;
        }
        Object bean = beanMethod.getBean();
        Method method = beanMethod.getMethod();
        try {
            System.out.println("=====执行服务方法:"+method); //执行
            return method.invoke(bean, rpcRequest.getArgs());
        } catch (IllegalAccessException |InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }
}
  • Bean后置处理器,容器创建后扫描自定义注解@RemoteService。
  • 拿到标注的类上的方法放入存储发布服务实例的map。
  • InitialMerdiator.java
//BeanPostProcessor
// 称Bean后置处理器,它是Spring中定义的接口,
// 在Spring容器的创建过程中(具体为Bean初始化前后)会回调BeanPostProcessor中定义的两个方法
@Component
public class InitialMerdiator implements BeanPostProcessor {
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean.getClass().isAnnotationPresent(RemoteService.class)) {//自定义服务发布注解
            Method[] methods = bean.getClass().getDeclaredMethods();
            for (Method method : methods) {
                String key = bean.getClass().getInterfaces()[0].getName() + "." + method.getName();
                BeanMethod beanMethod = new BeanMethod();
                beanMethod.setBean(bean);
                beanMethod.setMethod(method);
                Mediator.map.put(key, beanMethod);
            }
        }
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
}
  • 实现spring的 ApplicationListener
  • spring容器启动完成后会监听到一个ContextRedfreshdEvent事件
  • 拿到请求交给线程池处理AnnotationProcessorHandler(socket)
  • SocketServerInitial.java
//spring容器启动完成后会监听到一个ContextRedfreshdEvent事件
@Component
public class SocketServerInitial implements ApplicationListener<ContextRefreshedEvent> {
    private final ExecutorService executorService = Executors.newCachedThreadPool();
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        System.out.println("=====开始监听" + "=====端口:" + 8888);
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(8888);
            while (true) {
                Socket socket = serverSocket.accept();//监听请求
                System.out.println("=====收到请求" + socket);
                executorService.execute(new AnnotationProcessorHandler(socket));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

AnnotationProcessorHandler.java

public class AnnotationProcessorHandler implements Runnable{
    private Socket socket;
    public AnnotationProcessorHandler(Socket socket) {
        this.socket = socket;
    }
    @Override
    public void run() {
        //IO操作
        ObjectInputStream objectInputStream = null;
        ObjectOutputStream objectOutputStream = null;
        try {
            System.out.println("=====拿到客户端数据,反序列化");
            objectInputStream = new ObjectInputStream(socket.getInputStream());
            RpcRequest rpcRequest =(RpcRequest) objectInputStream.readObject();//反序列化

            Mediator mediator = Mediator.getInstance();//反射调用
            Object processor = mediator.processor(rpcRequest);//根据请求数据进行路由分发反射调用执行目标方法。
            System.out.println("=====服务端收到客户端请求处理后:"+processor);
            System.out.println("=====发送给客户端数据,序列化");
            objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            objectOutputStream.writeObject(processor);//返回给客户端
            objectOutputStream.flush();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }finally {
//            objectInputStream.close();
        }
    }
}
  • 启动容器,定义扫描包路径 BootStrap.java
@Configurable
@ComponentScan("com.example")
public class BootStrap {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(BootStrap.class);
    }

3.2.2 客户端实现

  • 定义注解 Target字段上 Refernce.java
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)//运行时用
@Component
public @interface Refernce {
}
  • 实现spring bean后置处理器,容器创建前扫描注解设置代理
  • RefernceInvokeProxy.java
  • 扫描到指定注解代理执行remoteInvocationHandler
@Component
public class RefernceInvokeProxy implements BeanPostProcessor {
    @Autowired
    RemoteInvocationHandler remoteInvocationHandler;
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        Field[] declaredFields = bean.getClass().getDeclaredFields();
        for (Field field : declaredFields) {
            if (field.isAnnotationPresent(Refernce.class)) {//对@Refernce注解设置代理
               Object proxy= Proxy.newProxyInstance(field.getType().getClassLoader(), new Class<?>[]{field.getType()}, remoteInvocationHandler);
                field.setAccessible(true);
                try {
                    field.set(bean,proxy);//对加@Refernce注解设置代理,实现inovcationHandler
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return bean;
    }
}
  • 实现InvocationHandler接口进行动态代理
  • RemoteInvocationHandler.java
  • send()发送数据
//实现 InvocationHandler动态代理
@Component
public class RemoteInvocationHandler implements InvocationHandler {
    @Value("${me.host}")
    private String host;
    @Value("${me.port}")
    private int port;

    public RemoteInvocationHandler(String host, int port) {
        this.host = host;
        this.port = port;
    }
    public RemoteInvocationHandler() {
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //建立远程连接
        RpcNetTransport rpcNetTransport = new RpcNetTransport(host, port);
//        Socket socket = rpcNetTransport.newSocket();
        System.out.println("====客户端建立远程连接");
//        传数据
        RpcRequest rpcRequest = new RpcRequest();
        rpcRequest.setClassName(method.getDeclaringClass().getName());//类名
        rpcRequest.setMethodName(method.getName());//方法名
        rpcRequest.setArgs(args);//参数
        rpcRequest.setTypes(method.getParameterTypes());//参数类型
        return rpcNetTransport.send(rpcRequest);//发送
    }
}
  • RpcNetTransport.java
  • RPC连接通道
  • 发送数据、响应结果
//RPC连接通道
public class RpcNetTransport {
    private String host;
    private int port;

    public RpcNetTransport(String host, int port) {
        this.host = host;
        this.port = port;
    }

    public Socket newSocket(){
        Socket socket = null;
        try {
            socket = new Socket(host, port);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return socket;
    }

    //发送
   public Object send(RpcRequest request){
        Socket socket = newSocket();
       System.out.println("=====发送:"+socket.toString());
       //IO操作
        ObjectInputStream objectInputStream = null;
        ObjectOutputStream objectOutputStream = null;
        try {
            objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            objectOutputStream.writeObject(request);//序列化
            System.out.println("=====序列化");
            objectOutputStream.flush();
            System.out.println("=====反序列化");
            objectInputStream = new ObjectInputStream(socket.getInputStream());
            Object object = objectInputStream.readObject();
            System.out.println("=====服务端返回结果:"+object);
            return object;
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }finally {
//            objectOutputStream.close();
        }
        return socket;
    }
}
  • 启动springboot
@SpringBootApplication
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class,args);
    }
  • 配置文件
  • 客户端启动8080,服务端启动8888
server.port=8080
me.host=127.0.0.1
me.port=8888
  • TestController.java
  • 访问8080controller接口得到服务端的回调结果。
@RestController
public class TestController {
    @Refernce
    IOrderService orderService;
    @GetMapping("/test")
    String get() {
        return orderService.selectOrderList();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值