1. 原理图示
引用段海涛老师 8天Hadoop视频课 原理图
注:
- 将controller,service都发布为服务(同一个jvm中可以直接通过方法调用,不通的jvm中可以通过网络传输数据);
- controller和service拥有共同的service接口;
- controller调用service接口的方法,底层通过socket程序将调用信息传输到service服务中(这一步可以通过动态代理实现,生成一个代理对象);
- service服务接收到调用信息以后,通过反射调用具体的方法;
- 将调用结果通过网络传输回controller。
2. 具体实现
2.1 服务端
服务端做两个操作:一 初始化service服务,以接口Protocol(这里指service接口)为key,具体实例为value放入map中;二 监听socket连接,获取客户端调用的Protocal, 方法(方法名,参数类型)、实参,通过map获取Protocol的实例,用反射调用获取结果,具体实现如下:
// 1. Server类
public class Server {
// 用来存放服务端实例化后的对象
private static Map<Class, Object> map = new HashMap<>();
public static void main(String[] args) throws Exception {
map.put(ILoginService.class, new LoginServiceImpl());
//服务端在20006端口监听客户端请求的TCP连接
ServerSocket server = new ServerSocket(20006);
Socket client = null;
boolean f = true;
while (f) {
//等待客户端的连接,如果没有获取连接
client = server.accept();
System.out.println("与客户端连接成功!");
//为每个客户端连接开启一个线程
new Thread(new ServerThread(client, map)).start();
}
server.close();
}
}
// 2. Server线程类
public class ServerThread implements Runnable {
public ServerThread(Socket client, Map<Class, Object> map) {
this.client = client;
this.map = map;
}
private Socket client;
private Map<Class, Object> map;
@Override
public void run() {
try {
//获取Socket的输出流,用来向客户端发送数据
ObjectOutputStream out = new ObjectOutputStream(client.getOutputStream());
//获取Socket的输入流,用来接收从客户端发送过来的数据
ObjectInputStream ois = new ObjectInputStream(client.getInputStream());
TData TData = (TData) ois.readObject();
Class<? extends TData> aClass = TData.getAClass();
Object[] args = TData.getArgs();
String methodName = TData.getMethodName();
Method method = aClass.getDeclaredMethod(methodName, TData.getParameterType());
Object object = method.invoke(map.get(aClass), args);
out.writeObject(object);
out.close();
client.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.2 客户端
客户端实现,以controller调用service方法为例子,首先获取Protocol(service接口)的代理类,其次在代理逻辑中,连接socket服务,传入Protocal、方法、参数(可以唯一确认方法)、实参到服务端获取结果,具体实现如下:
//1. 客户端类
public class Client {
public static void main(String[] args) {
ILoginService loginService = (ILoginService) Proxy.newProxyInstance(Main.class.getClassLoader(), new Class[]{ILoginService.class}, new SocketInvocationHandler(ILoginService.class));
String result = loginService.login("kangkang", "psd");
System.out.println(result);
}
}
// 2.代理逻辑实现类
public class SocketInvocationHandler implements InvocationHandler {
private Class aClass;
public SocketInvocationHandler(Class aClass) {
this.aClass = aClass;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//客户端请求与本机在20006端口建立TCP连接
Socket client = new Socket("127.0.0.1", 20006);
client.setSoTimeout(10000);
//获取Socket的输出流,用来发送数据到服务端
ObjectOutputStream out = new ObjectOutputStream(client.getOutputStream());
//获取Socket的输入流,用来接收从服务端发送过来的数据
ObjectInputStream buf = new ObjectInputStream(client.getInputStream());
TData TData = new TData();
TData.setAClass(aClass);
TData.setMethodName(method.getName());
TData.setParameterType(method.getParameterTypes());
TData.setArgs(args);
out.writeObject(TData);
Object object = buf.readObject();
return object.toString();
}
}
2.3 数据传输对象
由于走的是网络传输,所以对象需要序列化
@Data // lombok接口
public class TData implements Serializable {
private Class aClass;
private String methodName;
private Class<?>[] parameterType;
private Object[] args;
}
2.4 service
service接口和实现类就不罗列了只有一个简单的登录方法,可以自己写。