前提摘要:
- 之前的服务端已经实现了服务多个方法的响应(用request和respond封装),那么如果我有多个服务呢(BlogService、MentorService等)?
- 服务端过于耦合,不仅需要监听,还需要处理,全在RPCServer里,这显然不好。
调用多个服务
- 很关键的一点在于使用HashMap,自然的想到用一个Map来保存,<interfaceName, xxxServiceImpl>。
/**
* 存放服务接口名与服务端对应的实现类
* 服务启动时要暴露其相关的实现类
* 根据request中的interface调用服务端中相关实现类
*/
@Data
public class ServiceProvider {
/**
* 一个实现类可能实现多个接口
*/
private Map<String, Object> interfaceProvider;
public ServiceProvider(){
this.interfaceProvider = new HashMap<>();
}
public void provideServiceInterface(Object service){
String serviceName = service.getClass().getName();
Class<?>[] interfaces = service.getClass().getInterfaces();
for(Class clazz : interfaces){
interfaceProvider.put(clazz.getName(),service);
}
}
public Object getService(String interfaceName){
return interfaceProvider.get(interfaceName);
}
}
松耦合
嘿嘿,极致的松耦合,直接把原有的RPCServer变成接口
public interface RPCServer {
public void start(int port);
public void stop();
}
多线程服务端实现类(监听)其实还是BIO模式
- BIO:默认情况下服务端需要对每个请求建立一堆线程等待请求,而客户端发送请求后,先咨询服务端是否有线程相应,如果没有则会一直等待或者遭到拒绝请求,如果有的话,客户端会线程会等待请求结束后才继续执行。
public class ThreadPoolRPCRPCServer implements RPCServer {
private final ThreadPoolExecutor threadPool;
private Map<String, Object> serviceProvide;
public ThreadPoolRPCRPCServer(Map<String, Object> serviceProvide){
threadPool = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),
1000, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100));
this.serviceProvide = serviceProvide;
}
public ThreadPoolRPCRPCServer(Map<String, Object> serviceProvide, int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue){
threadPool = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
this.serviceProvide = serviceProvide;
}
@Override
public void start(int port) {
System.out.println("服务端启动了");
try {
ServerSocket serverSocket = new ServerSocket(port);
while(true){
Socket socket = serverSocket.accept();
threadPool.execute(new WorkThread(socket,serviceProvide));
}
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void stop() {
}
}
在这里我们用到的WorkThread类,即具体任务类代码如下(处理)
/**
这里负责解析得到的request请求,执行服务方法,返回给客户端
1. 从request得到interfaceName
2. 根据interfaceName在serviceProvide Map中获取服务端的实现类
3. 从request中得到方法名,参数, 利用反射执行服务中的方法
4. 得到结果,封装成response,写入socket
*/
@AllArgsConstructor
public class WorkThread implements Runnable{
private Socket socket;
private Map<String, Object> serviceProvide;
@Override
public void run() {
try {
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
// 读取客户端传过来的request
RPCRequest request = (RPCRequest) ois.readObject();
// 反射调用服务方法获得返回值
RPCResponse response = getResponse(request);
//写入到客户端
oos.writeObject(response);
oos.flush();
}catch (IOException | ClassNotFoundException e){
e.printStackTrace();
System.out.println("从IO中读取数据错误");
}
}
private RPCResponse getResponse(RPCRequest request){
// 得到服务名
String interfaceName = request.getInterfaceName();
// 得到服务端相应服务实现类
Object service = serviceProvide.get(interfaceName);
// 反射调用方法
Method method = null;
try {
method = service.getClass().getMethod(request.getMethodName(), request.getParamsTypes());
Object invoke = method.invoke(service, request.getParams());
return RPCResponse.success(invoke);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
System.out.println("方法执行错误");
return RPCResponse.fail();
}
}
}
-客户端我们就按直接的逻辑调用就好啦,以BlogService为例
BlogService blogService = clientProxy.getProxy(BlogService.class);
- 未完待续🥳