前言,这里使用jdk代理+bio短连接实现简易的RPC,后面会加强为Netty+Zookeeper+负载均衡算法的
我眼中的RPC:本地接口在使用动态代理,通过网络IO在远端节点进行了加强!
一、SimpleRPC 服务暴露和服务引用
package com.cloudwise.rpc.server;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @program mockjava1
* @description: Simple RPC Server demo by jdk
* @author: back
* @create: 2019/07/26 13:25
*/
public class SimpleRPC {
/**
* @description: 暴露服务
* @param: service 服务端实现
* @return:
* @author: back
* @date: 2019-07-26
**/
public static void export(final Object service,int port){
if(service == null)
throw new IllegalArgumentException("service is null");
if(port <= 0 || port > 65536)
throw new IllegalArgumentException("invalid port :"+port);
//System.out.println("export service :"+service.getClass().getName()+" on port "+port);
ExecutorService executor = Executors.newFixedThreadPool(10);
try {
ServerSocket ss = new ServerSocket(port);
while(true){
final Socket socket = ss.accept();
executor.execute(new ServiceHandler(socket,service));
}
} catch (IOException e) {
e.printStackTrace();
}finally {
executor.shutdown();
}
}
/**
* @description: 引用服务
* @param: <T>接口泛型 interfaceClass接口类型
* @return:
* @author: back
* @date: 2019-07-26
**/
public static <T> T refer(final Class<T> interfaceClass, final String host,final int port){
if(interfaceClass == null)
throw new IllegalArgumentException("interfaceClass is null");
if(!interfaceClass.isInterface())
throw new IllegalArgumentException("the interfaceClass must be interface");
if(port <= 0 || port > 65536)
throw new IllegalArgumentException("remoute port invalid port :"+port);
System.out.println("get remoute service "+interfaceClass.getName() +" from server");
return (T)Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class<?>[]{interfaceClass}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Socket socket = new Socket(host,port);
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
try {
oos= new ObjectOutputStream(socket.getOutputStream());
oos.writeUTF(method.getName());
oos.writeObject(method.getParameterTypes());
oos.writeObject(args);
ois = new ObjectInputStream(socket.getInputStream());
Object result = ois.readObject();
if(result instanceof Throwable)
throw (Throwable)result;
return result;
}finally {
ois.close();
oos.close();
socket.close();
}
}
});
}
}
二、ServiceHandler Server的处理逻辑
package com.cloudwise.rpc.server;
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;
/**
* @program mockjava1
* @description: thread for execute service handler
* @author: back
* @create: 2019/07/26 13:36
*/
public class ServiceHandler implements Runnable {
private Socket socket = null;
private Object service;
public ServiceHandler(Socket socket) {
this.socket = socket;
}
public ServiceHandler() {
}
public ServiceHandler(Socket socket, Object service) {
this.socket = socket;
this.service = service;
}
@Override
public void run() {
ObjectInputStream ois = null;
ObjectOutputStream oos = null;
try {
ois = new ObjectInputStream(socket.getInputStream());
String methodName = ois.readUTF();
Class<?>[] paramTypes = (Class<?>[])ois.readObject();
Object [] params = (Object[])ois.readObject();
oos = new ObjectOutputStream(socket.getOutputStream());
Method method = service.getClass().getMethod(methodName,paramTypes);
Object result = method.invoke(service,params);
oos.writeObject(result);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}finally {
try {
oos.close();
ois.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
三、提供者与消费者引用SimpleRPC后使用的例子
package com.cloudwise.provider;
import com.cloudwise.rpc.server.SimpleRPC;
import com.cloudwise.service.HelloService;
import com.cloudwise.service.impl.HelloServiceImpl;
import lombok.extern.slf4j.Slf4j;
/**
* @program mockjava1
* @description: bio rpc provider
* @author: back
* @create: 2019/07/26 14:46
*/
@Slf4j
public class SimpleProvider {
public static void main(String[] args) {
HelloService service = new HelloServiceImpl();
SimpleRPC.export(service,8000);
}
}
package com.cloudwise.client;
import com.cloudwise.rpc.server.SimpleRPC;
import com.cloudwise.service.HelloService;
import lombok.extern.slf4j.Slf4j;
/**
* @program mockjava1
* @description: consume the simple rpc service
* @author: back
* @create: 2019/07/26 14:49
*/
@Slf4j
public class SimpleConsumer {
public static void main(String[] args) {
HelloService service = SimpleRPC.refer(HelloService.class,"127.0.0.1",8000);
log.info("log println");
for (int i = 0; i < 10; i++) {
System.out.println(service.testRpcMethod("consumer"));
}
}
}