微服务已经是每个互联网开发者必须掌握的一项技术。而 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();
}
}
`