简易RPC框架

微服务已经是每个互联网开发者必须掌握的一项技术。而 RPC 框架,是构成微服务最重要的组成部分之一

先看一下简易rpc的调用流程

server端,通过自定义注解标记实现服务的注册(可以通过实现BeanPostProcessor在before之前进行处理,将标记的类存放到一个路由类的Map集合中,后续通过调用key来查找),client通过通过自定义注解标记实现服务的调用及参数的返回等,通过java的object对象输入输出流实现通信,在server端接收到后,去路由类匹配对应的类和方法,通过反射调用方法返回相应的参数,client接收参数并展示

api项目,接口类,接收传输过程中调用其他服务的方法及参数及接口名称等

`/**
 * @ClassName RpcRequest
 * @Description
 * @author lld
 * @version 2020-07-09 17:56
 */
@Data
public class RpcRequest implements Serializable{
    private String className;
    private String methodName;
    private Object[] args;
    private Class[] types;
}`
`/**
 * @ClassName
 * @Description
 * @author lld
 * @version 2020-07-09 17:47
 */
public interface IOrderService {


    String queryOrderList();

    String orderById(String id);
}`

通过maven将api项目部署到本地中(mvn install),并在pom.xml中加入api的引用

	<dependency>
        <artifactId>api</artifactId>
        <groupId>com.gok.edu.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </dependency>

server端order项目,对IOrderService接口的实现OrderServiceImpl,通过注解的形式来标记该接口实现类,在装载时进行对标记的类进行处理

server端 @RemoteService
	`@Component
	//注解的使用地点为 类,接口或enum声明
	@Target({ElementType.TYPE})
	//注解的声明周期为始终不会丢弃
	@Retention(RetentionPolicy.RUNTIME)
	public @interface RemoteService {
	}`
client端 @RefenceAnnotation
//注解的字段、枚举的常量
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface RefenceAnnotation {
}`

连接通信,通过socket连接通信

server端,通过实现ApplicationListener,重写onApplicationEvent来实现启动时启动socket服务
`   package com.gok.edu.example;
	import org.springframework.beans.factory.annotation.Value;
	import org.springframework.context.ApplicationListener;
	import org.springframework.context.event.ContextRefreshedEvent;
	import org.springframework.stereotype.Component;
	
	import java.io.IOException;
	import java.io.ObjectInputStream;
	import java.io.ObjectOutputStream;
	import java.net.ServerSocket;
	import java.net.Socket;
	import java.util.concurrent.ExecutorService;
	import java.util.concurrent.Executors;
	
	@Component
	public class SocketServiceChanle implements ApplicationListener<ContextRefreshedEvent> {
	
	    @Value("${sk.port}")
	    private Integer port;
	
	    private final ExecutorService executorService = Executors.newCachedThreadPool();
	
	
	    @Override
	    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
	        try(ServerSocket serverSocket = new ServerSocket(port)){
	            while(true){
	                Socket socket = serverSocket.accept();
	                executorService.execute(()->{
	
	                    try(ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
	                        ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream());
	                        ){
	                        RpcRequest request=(RpcRequest)inputStream.readObject(); //反序列化
	                        //路由,通过标记的类获取
	                        Mediator mediator=Mediator.getInstance();
	                        Object rs=mediator.process(request);
	                        System.out.println("服务端的执行结果:"+rs);
	                        outputStream.writeObject(rs);
	                        outputStream.flush();
	
	                    } catch (IOException e) {
	                        e.printStackTrace();
	                    } catch (ClassNotFoundException e) {
	                        e.printStackTrace();
	                    }
	
	                });
	
	
	
	            }
	
	        } catch (IOException e) {
	            e.printStackTrace();
	        }
	
	    }
	}

`

client
`   public Object send(RpcRequest request) throws IOException {
        Socket socket = newSocket();
        try(ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream());
            ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());){
            outputStream.writeObject(request);
            outputStream.flush();
            return inputStream.readObject();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }`

通过实现BeanPostProcessor接口实现postProcessBeforeInitialization方法,找到注解所标记的类或接口或方法等,进行处理

server 端通过before方法将标记的类的信息存储到路由类的Map中
`package com.gok.edu.example;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Component
public class MediatorInitail implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

        Class clazz = bean.getClass();
        //判断bean是否为自定义注解标记过得
        if(clazz.isAnnotationPresent(RemoteService.class)){
            Method[] methods = clazz.getDeclaredMethods();
            for (Method method : methods) {
                String key = clazz.getInterfaces()[0].getName() + "." + method.getName();
                BeanMethod beanMethod = new BeanMethod();
                beanMethod.setBean(bean);
                beanMethod.setMethod(method);
                //添加到路由map中
                Mediator.map.put(key,beanMethod);
            }
        }
        return bean;
    }
}

`

client 端通过before方法将标记的类设置一个jdk自带的动态代理,当Controller调用类变量时,去代理类上执行
`package com.gok.edu.example;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Proxy;

/**
 * @ClassName 
 * @Description
 * @author lld
 * @version 2020-07-10 14:04
 */
@Component
public class RefenceInvocationProxy implements BeanPostProcessor {



    @Autowired
    private RefenceInvocationHandle invocationHandler;

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        Class clazz = bean.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field:fields) {
            if(field.isAnnotationPresent(RefenceAnnotation.class)){
                Object proxy= Proxy.newProxyInstance(field.getType().getClassLoader(),new Class<?>[]{field.getType()},invocationHandler);
                //设置私有访问
                field.setAccessible(true);
                try {
                    //对调用自定义标记的方法加一个代理
                    field.set(bean,proxy);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return bean;
    }
}

`

client端通过jdk动态代理实现
package com.gok.edu.example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
 * @ClassName
 * @Description
 * @author lld
 * @version 2020-07-10 10:10
 */
@Component
public class RefenceInvocationHandle implements InvocationHandler {

    @Value("${sk.host}")
    private String host;

    @Value("${sk.port}")
    private Integer port;

    public RefenceInvocationHandle() {
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //建立socket连接,通过socket进行传输数据,通过对象封装数据
        SocketChannle socketChannle = new SocketChannle(host,port);
        RpcRequest request = new RpcRequest();
        request.setArgs(args);
        request.setClassName(method.getDeclaringClass().getName());
        request.setTypes(method.getParameterTypes());
        request.setMethodName(method.getName());
        //通过socket进行通信
        return socketChannle.send(request);
    }
}

在server端order实现接口

package com.gok.edu.example;

/**
 * @ClassName 
 * @Description
 * @author lld
 * @version 2020-07-10 11:10
 */

@RemoteService
public class OrderServiceImpl implements IOrderService{

    @Override
    public String queryOrderList() {
        return "list";
    }

    @Override
    public String orderById(String id) {
        return id;
    }
}

client端实现跨服务调用接口

`package com.gok.edu.example;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @ClassName
 * @Description
 * @author lld
 * @version 2020-07-10 14:04
 */
@RestController
public class TestController {

    @RefenceAnnotation
    private IOrderService orderService;

    @RefenceAnnotation
    private ITestService testService;


    @GetMapping("/list")
    public String findList(){
        return orderService.queryOrderList();
    }

    @GetMapping("/test")
    public String test(){
        return testService.test();
    }
}

`

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值