在上一篇博客中,完成了一个极简的demo,其缺点也是显而易见,服务端只能注册一个服务,在实际工作中,这肯定是无法接受的,所以,本篇博文的目的在于实现多服务注册,并且,注册中心和服务端不应该集成在一起,这会使得系统耦合度太高。
服务注册表
注册表提供了两个功能:1服务注册到注册表中。2根据服务名获取服务实体
public interface ServiceRegistry { /** * 将一个服务注册进注册表 * @param service 待注册的服务实体 * @param <T> 服务实体类 */ <T> void register(T service); /** * 根据服务名称获取服务实体 * @param serviceName 服务名称 * @return 服务实体 */ Object getService(String serviceName); }
实现用的是map和set,用map存储服务名和服务对象的对应关系,用set保存当前哪些对象被注册。获取服务对象直接用map查询。
public class DefaultServiceRegistry implements ServiceRegistry { private static final Logger logger = LoggerFactory.getLogger(DefaultServiceRegistry.class); private final Map<String, Object> serviceMap = new ConcurrentHashMap<>(); private final Set<String> registeredService = ConcurrentHashMap.newKeySet(); @Override public synchronized <T> void register(T service) { String serviceName = service.getClass().getCanonicalName(); if(registeredService.contains(serviceName)) return; registeredService.add(serviceName); Class<?>[] interfaces = service.getClass().getInterfaces(); if(interfaces.length == 0) { throw new RpcException(RpcError.SERVICE_NOT_IMPLEMENT_ANY_INTERFACE); } for(Class<?> i : interfaces) { serviceMap.put(i.getCanonicalName(), service); } logger.info("向接口: {} 注册服务: {}", interfaces, serviceName); } @Override public synchronized Object getService(String serviceName) { Object service = serviceMap.get(serviceName); if(service == null) { throw new RpcException(RpcError.SERVICE_NOT_FOUND); } return service; } }
注册中心和服务端分开
为了降低耦合度,在创建一个RpcServer的时候,传入一个服务注册表ServiceRegistry.
public class RpcServer { private static final Logger logger = LoggerFactory.getLogger(RpcServer.class); private static final int CORE_POOL_SIZE = 5; private static final int MAXIMUM_POOL_SIZE = 50; private static final int KEEP_ALIVE_TIME = 60; private static final int BLOCKING_QUEUE_CAPACITY = 100; private final ExecutorService threadPool; private RequestHandler requestHandler = new RequestHandler(); private final ServiceRegistry serviceRegistry; public RpcServer(ServiceRegistry serviceRegistry) { this.serviceRegistry = serviceRegistry; BlockingQueue<Runnable> workingQueue = new ArrayBlockingQueue<>(BLOCKING_QUEUE_CAPACITY); ThreadFactory threadFactory = Executors.defaultThreadFactory(); threadPool = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS, workingQueue, threadFactory); } public void start(int port) { try (ServerSocket serverSocket = new ServerSocket(port)) { logger.info("服务器启动……"); Socket socket; while((socket = serverSocket.accept()) != null) { logger.info("消费者连接: {}:{}", socket.getInetAddress(), socket.getPort()); threadPool.execute(new RequestHandlerThread(socket, requestHandler, serviceRegistry)); } threadPool.shutdown(); } catch (IOException e) { logger.error("服务器启动时有错误发生:", e); } } }
工作线程也从WorkerThread转化为RequestHandlerThread,初始化工作线程的时候需要传入requestHandler和serviceRegistry,工作线程负责两件事:从字节流中读取rpcrequest对象,找到服务对象,调用服务,调用服务通过requestHandler.handle实现。
@Override public void run() { try (ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream()); ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream())) { RpcRequest rpcRequest = (RpcRequest) objectInputStream.readObject(); String interfaceName = rpcRequest.getInterfaceName(); Object service = serviceRegistry.getService(interfaceName); Object result = requestHandler.handle(rpcRequest, service); objectOutputStream.writeObject(RpcResponse.success(result)); objectOutputStream.flush(); } catch (IOException | ClassNotFoundException e) { logger.error("调用或发送时有错误发生:", e); } }
调用服务的实现:
public class RequestHandler { private static final Logger logger = LoggerFactory.getLogger(RequestHandler.class); public Object handle(RpcRequest rpcRequest, Object service) { Object result = null; try { result = invokeTargetMethod(rpcRequest, service); logger.info("服务:{} 成功调用方法:{}", rpcRequest.getInterfaceName(), rpcRequest.getMethodName()); } catch (IllegalAccessException | InvocationTargetException e) { logger.error("调用或发送时有错误发生:", e); } return result; } private Object invokeTargetMethod(RpcRequest rpcRequest, Object service) throws IllegalAccessException, InvocationTargetException { Method method; try { method = service.getClass().getMethod(rpcRequest.getMethodName(), rpcRequest.getParamTypes()); } catch (NoSuchMethodException e) { return RpcResponse.fail(ResponseCode.METHOD_NOT_FOUND); } return method.invoke(service, rpcRequest.getParameters()); } }
小结:功能上增加了注册表实现服务注册和获取服务对象,并且对工作线程做了更细致的设计。