手写RPC框架

RPC框架的实现过程

1.注册中心
    a.本地注册,需要的参数是   接口名,ip和端口
    b.开启ServerSocket 服务端,注册服务
    c.开启线程,返回 服务注册信息
2.服务端
    a.接口 实现类注册
    b.开启服务端,等待客户端请求,返回结果
3.客户端
    a.动态代理处理服务端请求  需要的参数是   接口名,方法名,方法参数列表,方法参数
    b.结果返回
 

简易RPC框架(无注册中心)

服务端

package com.hikktn.center;

/**
 * @ClassName App
 * @Description TODO
 * @Author lisonglin
 * @Date 2021/3/23 21:16
 * @Version 1.0
 */
public class App {
	public static void main(String[] args){
		HelloService helloService = new HelloServiceImpl();
		RegisterCenter registerCenter=new RegisterCenter();
		registerCenter.start(helloService,8888);
	}
}
package com.hikktn.center;

import java.io.IOException;
import java.net.ServerSocket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @ClassName RegisterCenter
 * @Description TODO
 * @Author lisonglin
 * @Date 2021/3/22 17:57
 * @Version 1.0
 */
public class RegisterCenter {

	// 线程池准备
	private static ExecutorService executor = Executors.newFixedThreadPool(1);
	// 准备一个服务端
	private ServerSocket serverSocket = null;

	public RegisterCenter(){

	}


	// 开启一个线程
	public void start(Object service,int port){
		// 开启服务端
		try {
			System.out.println("服务端开启");
			serverSocket = new ServerSocket(port);
			// 等待线程唤醒
			while(true){
				// 接收客户端发送的各种数据
				executor.execute(new ProcessorHandler(serverSocket.accept(),service));
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}
package com.hikktn.center;

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

/**
 * @ClassName ProcessorHandler
 * @Description TODO
 * @Author lisonglin
 * @Date 2021/3/23 20:50
 * @Version 1.0
 */
public class ProcessorHandler implements Runnable {
	Socket socket;
	Object service;

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

	public ProcessorHandler() {
	}

	@Override
	public void run() {
		ObjectInputStream is = null;
		ObjectOutputStream os = null;
		try {
			is = new ObjectInputStream(socket.getInputStream());
			RpcRequest request =(RpcRequest) is.readObject();
			// 只是调用接口执行
			Object result = invoke(request);
			System.out.println("服务端的结果"+result);
			os = new ObjectOutputStream(socket.getOutputStream());
			os.writeObject(result);
			os.flush();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}finally {
			try {
				is.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				os.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}

	private Object invoke(RpcRequest request) {
		// 获取方法中的参数类型
		Class<?>[] parameterTypes = request.getParameterTypes();
		// 获取执行方法传入的参数
		Object[] parameters = request.getParameters();

		try {
			// 接口类根据执行方法名和参数类型,返回一个方法类
			Method method = service.getClass().getMethod(request.getMethodName(), parameterTypes);
			// 调用接口实现类和参数值返回结果
			Object invoke = method.invoke(service, parameters);
			return invoke;
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		return null;
	}
}
package com.hikktn.center;

import java.io.Serializable;
import java.util.Arrays;

/**
 * @ClassName RpcRequest
 * @Description 提供服务
 * @Author lisonglin
 * @Date 2021/3/19 0:59
 * @Version 1.0
 */
public class RpcRequest implements Serializable {

	private static final long serialVersionUID = -4403913516658154989L;

	private String className; //类名称,全包路径
	private String methodName; //执行方法名
	private Class<?>[] parameterTypes; //方法中的参数类型
	private Object[] parameters; //执行方法传入的参数

	public String getClassName() {
		return className;
	}

	public void setClassName(String className) {
		this.className = className;
	}

	public String getMethodName() {
		return methodName;
	}

	public void setMethodName(String methodName) {
		this.methodName = methodName;
	}

	public Class<?>[] getParameterTypes() {
		return parameterTypes;
	}

	public void setParameterTypes(Class<?>[] parameterTypes) {
		this.parameterTypes = parameterTypes;
	}

	public Object[] getParameters() {
		return parameters;
	}

	public void setParameters(Object[] parameters) {
		this.parameters = parameters;
	}

	@Override
	public String toString() {
		return "RpcRequest{" + "className='" + className + '\'' + ", methodName='" + methodName + '\'' + ", parameterTypes=" + Arrays.toString(parameterTypes) + ", parameters=" + Arrays.toString(parameters) + '}';
	}
}

客户端

package com.hikktn.center;

/**
 * @ClassName App
 * @Description TODO
 * @Author lisonglin
 * @Date 2021/3/23 20:59
 * @Version 1.0
 */
public class App {

	public static void main(String[] args){
		RpcClientProxy rpcClientProxy = new RpcClientProxy();
		HelloService helloService = rpcClientProxy.clientProxy(HelloService.class, "localhost", 8888);
		String sayHello = helloService.sayHello(1, 2);
		System.out.println(sayHello);
	}
}
package com.hikktn.center;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @ClassName RpcClientProxy
 * @Description TODO
 * @Author lisonglin
 * @Date 2021/3/23 21:01
 * @Version 1.0
 */
public class RpcClientProxy {

	public <T> T clientProxy(Class<T> interfaceCls,String host,int port){
		return (T) Proxy.newProxyInstance(interfaceCls.getClassLoader(), new Class<?>[]{interfaceCls},new Handler(host,port));
	}
}
package com.hikktn.center;

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

/**
 * @ClassName Handler
 * @Description TODO
 * @Author lisonglin
 * @Date 2021/3/23 21:05
 * @Version 1.0
 */
public class Handler implements InvocationHandler {

	String host;
	int post;

	public Handler(String host, int post) {
		this.host = host;
		this.post = post;
	}


	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		RpcRequest request = new RpcRequest();
		// 类名称,全包路径
		request.setClassName(method.getDeclaringClass().getName());
		// 执行方法名
		request.setMethodName(method.getName());
		// 方法中的参数类型
		request.setParameterTypes(method.getParameterTypes());
		// 执行方法传入的参数
		request.setParameters(args);
		Socket socket = null;
		ObjectInputStream objectInputStream = null;
		ObjectOutputStream objectOutputStream = null;
		Object result =null;
		try {
			socket =new Socket(host,post);
			objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
			objectOutputStream.writeObject(request);
			objectOutputStream.flush();

			objectInputStream =new ObjectInputStream(socket.getInputStream());
			result = objectInputStream.readObject();

		}catch (IOException e){
			e.printStackTrace();
		}finally {
			objectInputStream.close();
			objectOutputStream.close();
		}

		return result;
	}
}

复杂版

原视频地址

https://www.bilibili.com/video/BV1yE411b7PA?p=8

分析

客户端
    1.读取配置
        a.扫描存放接口实现类的包----consumer.xml
        b.注入远程调用@Reference的类----LinkConsumerProcess.java
            A. 初始化之前进行的业务实现--postProcessBeforeInitialization()
            B. 初始化之后进行的业务实现--postProcessAfterInitialization()
                a. 获取@Reference属性 【private】 【com.hikktn.service.AddService】 【com.hikktn.service.impl.ConsumerServiceImpl.addService】,循环Field属性
                b.修改安全访问属性
                c.获取存在Reference注解的接口
                d.如果Reference注解存在
                    1.1 获取该接口类型
                    1.2 动态代理返回bean
注册中心

服务端
    1.读取配置-----ClassMateApp.java
        a.扫描存放接口实现类的包-----provider.xml
        b.注入Spring包扫描机制-----LinkProviderContext.java
            A.通过ApplicationContextAware扫描到接口和接口实现类--setApplicationContext()
                a.扫描@Servier注解生成bean
                b.根据bean的数量循环
                    1.1 获取接口名,包括包的路径
                    1.2 设置服务地址
            B.加载初始化--afterPropertiesSet()
                a.获取服务地址------ServerRegeisterZkImpl.regeister()
                    1.1 服务注册-----------ZKUtil.writeServiceNode()
                        A.连接zookeeper实现注册
                            a.如果节点存在的场合
                                1.1.1 创建持久化节点
                            b.反之
                                1.1.2 创建临时节点
                b.开启线程池,监听客户端请求
                    1.1 开启服务端套接字,端口8888----ProviderServerSocketImpl.listener(port)
                    1.2 始终等待客户端消息
                    1.3 当客户端发送请求,获取客户端请求源--invoker()
                        A. 获取客户端输入流--getData()
                        B. 将客户端输入流反序列化为对象,对象存储着【类名称】、【执行方法名】、【方法中的参数列表】、【执行方法传入的参数】
                        C. 获取类名称
                        D. 获取执行方法名
                        F. 获取方法中的参数类型
                        E. 获取执行方法传入的参数
                        G. 接收客户端的结果----LocalMethodHandler.invoker()
                            1.1.1 执行动态代理代理
                                a. 根据类名创建接口class对象
                                b. 获取接口的实现类-----LinkProviderContext.applicationContext.getBean(interfaceClass)
                                c. 根据接口对象的方法名,方法里面的参数类型,获取一个方法对象
                                d. 根据该方法对象代理接口实现类,将参数进行动态代理运行,得到结果
                            1.1.2 设置返回响应
                                a. 将结果返回
                                b. 序列化返回客户端结果
    2.启动服务
    3.设置输入源,等待请求

源码:

项目地址

链接:https://pan.baidu.com/s/1GSqbpvtqlxgaLJQb56TJLQ 
提取码:16xj 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hikktn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值