目录
GitHub地址
https://github.com/Asperger12345/shenrpc-spring-boot-starter
文件目录
Message
传递的消息载体类
package com.shen.api;
import lombok.Builder;
import lombok.Data;
import java.io.Serializable;
@Data
@Builder
public class Message implements Serializable {
//服务接口名
private String className;
//方法名
private String methodName;
//参数
private Object[] args;
//接口类型
private Class[] types;
}
consumer
服务消费方
@EnableRpcConsumer
打在SpringBoot启动类上
package com.shen.api.consumer;
import org.springframework.context.annotation.Import;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import({ReferenceInvokeProxy.class,RpcHandler.class})
public @interface EnableRpcConsumer {
}
@Reference
打在注入的接口上
package com.shen.api.consumer;
import org.springframework.stereotype.Component;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface Reference {
}
ReferenceInvokeProxy
对于每个有 @Reference 注解的接口,生成代理
package com.shen.api.consumer;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
public class ReferenceInvokeProxy implements BeanPostProcessor {
@Autowired
RpcHandler invocationHandler;
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
Field[] fields=bean.getClass().getDeclaredFields();
for(Field field:fields){
if(field.isAnnotationPresent(Reference.class)){
field.setAccessible(true);
Object proxy= Proxy.newProxyInstance(field.getType().getClassLoader(),new Class<?>[]{field.getType()},invocationHandler);
try {
field.set(bean,proxy);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
return bean;
}
}
RpcHandler
让接口生成代理
调用服务的方法,实际上是在进行 BIO 通信
通过在 application.properties 配置 provider.host,provider.port,确定提供方主机号、端口号
package com.shen.api.consumer;
import com.shen.api.Message;
import org.springframework.beans.factory.annotation.Value;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.net.Socket;
public class RpcHandler implements InvocationHandler {
@Value("${provider.host}")
private String host;
@Value("${provider.port}")
private int port;
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Socket socket = new Socket(host, port);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
Message message = Message.builder()
.className(method.getDeclaringClass().getName())
.methodName(method.getName())
.args(args)
.types(method.getParameterTypes()).build();
objectOutputStream.writeObject(message);
objectOutputStream.flush();
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
return objectInputStream.readObject();
}
}
provider
服务提供方
@EnableRpcProvider
打在SpringBoot启动类上
package com.shen.api.provider;
import org.springframework.context.annotation.Import;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import({SocketServerInitial.class,InitialMediator.class,})
public @interface EnableRpcProvider {
}
@Service
打在提供的服务实现类上
package com.shen.api.provider;
import org.springframework.stereotype.Component;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface Service {
}
BeanMethod
封装所有提供的类和方法
package com.shen.api.provider;
import lombok.Data;
import java.lang.reflect.Method;
@Data
public class BeanMethod {
private Object bean;
private Method method;
}
InitialMediator
对于每个打了自定义的 @Service 的实例化后的 Bean,遍历所有方法,以"接口名.方法名"为key,存储实现类类名和方法名的封装到 map 中
package com.shen.api.provider;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import java.lang.reflect.Method;
public class InitialMediator implements BeanPostProcessor {
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(bean.getClass().isAnnotationPresent(Service.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 bean;
}
}
Mediator
"接口名.方法名"为key,存储实现类类名和方法名的封装
根据实现类类名和方法名,反射调用本地方法,给出返回值
package com.shen.api.provider;
import com.shen.api.Message;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class Mediator {
public static Map<String ,BeanMethod> map=new ConcurrentHashMap();
private volatile static Mediator instance;
private Mediator(){}
public static Mediator getInstance(){
if(instance==null){
synchronized (Mediator.class){
if(instance==null){
instance=new Mediator();
}
}
}
return instance;
}
public Object process(Message message){
String key=message.getClassName()+"."+message.getMethodName();
BeanMethod beanMethod=map.get(key);
if(beanMethod==null){
return null;
}
Object bean=beanMethod.getBean();
Method method=beanMethod.getMethod();
try {
return method.invoke(bean,message.getArgs());
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}
ServiceHandler
伪异步处理 Message
package com.shen.api.provider;
import com.shen.api.Message;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
public class ServiceHandler implements Runnable {
private Socket socket;
public ServiceHandler(Socket socket) {
this.socket = socket;
}
public void run() {
ObjectInputStream objectInputStream = null;
ObjectOutputStream outputStream = null;
try {
objectInputStream = new ObjectInputStream(socket.getInputStream());
Message message = (Message) objectInputStream.readObject();
Mediator mediator=Mediator.getInstance();
Object rs=mediator.process(message);
outputStream = new ObjectOutputStream(socket.getOutputStream());
outputStream.writeObject(rs);
outputStream.flush();
} catch (Exception e) {
e.printStackTrace();
}finally {
if(objectInputStream != null) {
try {
objectInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(outputStream != null) {
try {
objectInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
SocketServerInitial
容器 Refresh 后,调用此方法监听请求。
通过在 application.properties 配置 provider.port,确定提供方端口号。
package com.shen.api.provider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SocketServerInitial implements ApplicationListener<ContextRefreshedEvent> {
private final ExecutorService executorService= Executors.newCachedThreadPool();
@Value("${provider.port}")
private int port;
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
ServerSocket serverSocket=null;
try {
serverSocket=new ServerSocket(port);
while(true){
Socket socket=serverSocket.accept();
executorService.execute(new ServiceHandler(socket));
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if(serverSocket!=null){
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
示例
consumer
启动类
package com.shen.consumer;
import com.shen.api.consumer.EnableRpcConsumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan("com.shen.consumer")
@EnableRpcConsumer
public class BootStrap {
public static void main(String[] args) {
SpringApplication.run(BootStrap.class,args);
}
}
配置文件
provider.host = localhost
provider.port = 8888
server.port=8080
TestController
package com.shen.consumer;
import com.shen.api.ExampleService;
import com.shen.api.consumer.Reference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@Reference
ExampleService exampleService;
@GetMapping("/test")
public String test(){
return exampleService.info();
}
}
provider
启动类
package com.shen.provider;
import com.shen.api.provider.EnableRpcProvider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan("com.shen.provider")
@EnableRpcProvider
public class BootStrap {
public static void main(String[] args) {
SpringApplication.run(BootStrap.class,args);
}
}
配置文件
provider.port = 8888
server.port=8081
ExampleServiceImpl
package com.shen.provider.service;
import com.shen.api.ExampleService;
import com.shen.api.provider.Service;
@Service
public class ExampleServiceImpl implements ExampleService {
public String info() {
return "example";
}
}