随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,就需一个治理系统确保架构有条不紊的演进,Dubbo由此产生。
Dubbo 架构
节点角色说明
节点 | 说明 |
---|---|
Provider | 暴露服务的服务提供方 |
Consumer | 调用远程服务的服务消费方 |
Registry | 服务注册与发现的注册中心 |
Monitor | 统计服务的调用次数和调用时间的监控中心 |
Container | 服务运行器 |
调用关系说明
- 服务容器负责启动,加载,运行服务提供者。
- 服务提供者在启动时,向注册中心注册自己提供的服务。
- 服务消费者在启动时,向注册中心订阅自己所需的服务。
- 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
- 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
- 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
简易Dubbo实现
1. Dubbo API
新建一个maven项目,项目结构如下:
1.1 编写DTO
1.1.1 客户端到服务器的标准DTO
RPCCommonReqDTO
@Data
public class RPCCommonReqDTO implements Serializable {
private static final long serialVersionUID = 1540605806624661461L;
// 服务调用实现类全路径
private String classPath;
// 方法名称
private String methodName;
// 方法参数s
private Object[] args;
}
1.1.2 其他DTO
UserDTO
@Data
public class UserDTO implements Serializable {
private static final long serialVersionUID = 2320008609104776008L;
private String id;
private String name;
private Integer age;
private String sex;
}
OrgDto
@Data
public class OrgDto implements Serializable {
private static final long serialVersionUID = -2463193363004747278L;
private String id;
private String parentId;
private String name;
private String code;
}
1.2 定义服务接口
OrgService
// 服务实现类全路径
@ImplAnnotion("com.lizq.api.impl.OrgServiceImpl")
public interface OrgService {
/**
* 添加组织
* @param org
* @return
*/
OrgDto addOrg(OrgDto org);
}
UserService
@ImplAnnotion("com.lizq.api.impl.UserServiceImpl")
public interface UserService {
/**
* 添加用户
* @param user
* @return
*/
UserDTO addUser(UserDTO user);
}
1.3 定义获取服务实现类全路径Annotion
@ImplAnnotion
/**
* 用于标识该服务实现类全路径
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ImplAnnotion {
String value();
}
执行 mvn clean install 将 rpc-api 打为 jar 包已供Provider、Consumer引用。
2. Provider
新建一个maven项目,项目结构如下
引入 rpc-api 依赖
2.1 编写服务接口实现类
编写服务接口实现类
UserServiceImpl
public class UserServiceImpl implements UserService {
@Override
public UserDTO addUser(UserDTO userDTO) {
// TODO 参数验证、数据新增
userDTO.setId(UUID.randomUUID().toString());
return userDTO;
}
}
OrgServiceImpl
public class OrgServiceImpl implements OrgService {
@Override
public OrgDto addOrg(OrgDto orgDto) {
// TODO 参数验证、数据新增
orgDto.setId(UUID.randomUUID().toString());
return orgDto;
}
}
2.2 编写请求服务类
NetServer
public class NetServer {
private static final ExecutorService executorService = Executors.newFixedThreadPool(100);
public static void start(int port) {
try {
ServerSocket serverSocket = new ServerSocket(port);
while (true) {
// 阻塞等待客户端连接
Socket socket = serverSocket.accept();
// 开启线程处理客户端连接
executorService.submit(new RPCThreadProcessor(socket));
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// 启动
NetServer.start(8888);
}
}
2.3 编写处理服务消费请求线程类
RPCThreadProcessor
public class RPCThreadProcessor implements Runnable {
private Socket socket;
public RPCThreadProcessor(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try (
ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream());
) {
Object object = inputStream.readObject();
// 进行服务的调用与分发 Service Dispatch
Object obj = ServiceDispatch.dispatch(object);
outputStream.writeObject(obj);
outputStream.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.4 编写服务的分发与调用类
ServiceDispatch
public class ServiceDispatch {
public static Object dispatch(Object object) {
RPCCommonReqDTO rpcCommonReqDTO = (RPCCommonReqDTO) object;
String classPath = rpcCommonReqDTO.getClassPath();
String methodName = rpcCommonReqDTO.getMethodName();
Object[] args = rpcCommonReqDTO.getArgs();
Class[] paramsClass = null;
// 获取参数 Class 数组
if (args != null && args.length > 0) {
paramsClass = new Class[args.length];
for (int i = 0; i < args.length; i++) {
paramsClass[i] = args[i].getClass();
}
}
Object obj = null;
try {
Class clazz = Class.forName(classPath);
// 获取调用方法对象
Method method = clazz.getDeclaredMethod(methodName, paramsClass);
// 通过反射的方式调用方法
obj = method.invoke(clazz.newInstance(), args);
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
}
启动 rpc-provider 监听服务消费请求
3. Consumer
新建一个maven项目,项目结构如下
引入 rpc-api 依赖
3.1 编写获取服务工厂类
ProxyFactory
public class ProxyFactory {
public static <T> T getServiceInstance(Class<T> interfaceClass) {
return (T) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{interfaceClass}, new InvocationHandler() {
/**
* ProxyInstance
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
RPCCommonReqDTO rpcCommonReqDTO = new RPCCommonReqDTO();
ImplAnnotion implAnnotion = interfaceClass.getAnnotation(ImplAnnotion.class);
if (implAnnotion != null) {
rpcCommonReqDTO.setClassPath(implAnnotion.value());
rpcCommonReqDTO.setMethodName(method.getName());
rpcCommonReqDTO.setArgs(args);
// 通过 socket 调用服务
return NetClient.callServer("localhost", 8888, rpcCommonReqDTO);
}
return null;
}
});
}
}
3.2 编写调用服务类
NetClient
public class NetClient {
public static Object callServer(String host, int port, RPCCommonReqDTO rpcCommonReqDTO){
Object obj = null;
ObjectInputStream inputStream = null;
ObjectOutputStream outputStream = null;
try {
Socket socket = new Socket(host, port);
outputStream = new ObjectOutputStream(socket.getOutputStream());
inputStream = new ObjectInputStream(socket.getInputStream());
outputStream.writeObject(rpcCommonReqDTO);
outputStream.flush();
obj = inputStream.readObject();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (inputStream != null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outputStream != null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return obj;
}
}
3.3 调用测试
public class Call {
public static void main(String[] args) {
UserService userService = ProxyFactory.getServiceInstance(UserService.class);
UserDTO user = new UserDTO();
user.setName("test1");
user.setAge(88);
user.setSex("男");
System.out.println("入参:" + user);
System.out.println("出差:" + userService.addUser(user));
System.out.println("=========================================================");
OrgService orgService = ProxyFactory.getServiceInstance(OrgService.class);
OrgDto org = new OrgDto();
org.setName("财务部");
org.setCode("CWB");
org.setParentId("0");
System.out.println("入参:" + org);
System.out.println("出差:" + orgService.addOrg(org));
}
}
执行结果:
入参:UserDTO(id=null, name=test1, age=88, sex=男)
出差:UserDTO(id=871f08a6-f537-4298-8b71-44a849a63842, name=test1, age=88, sex=男)
=========================================================
入参:OrgDto(id=null, parentId=0, name=财务部, code=CWB)
出差:OrgDto(id=e4bb7e3d-23ee-478c-867b-07e1f4465b64, parentId=0, name=财务部, code=CWB)