文章目录
1 SOA的理解
1.1 基本理解
SOA
英文名称(Service Oriented Ambiguity
),中文名称:面向服务架构
,有一个专门提供服务单元,其他所有单元都调用这个服务.
SOA
定位:如何设计项目,让开发时更有效率.,SOA
是一种思想
1.2 没用SOA
之前项目架构设计:在公司项目不允许所有项目都访问数据库,开发时,数据库访问层代码可能出现冗余
1.3 使用SOA
使用SOA
架构:专门访问数据库服务(项目),开发时可以实现,数据访问控制和代码复用
实现SOA
架构时,常用服务:
Dubbo
做为服务.WebService
做为服务.Dubbox
做为服务.- 服务方就是
web
项目,调用web
项目的控制器,使用HttpClient
可以调用其他项目的控制器.
2 RPC
2.1 定义
RPC
英文名称(Remote Procedure Call Protocol
),中文名称:远程过程调用协议
RPC
解析:客户端(A
)通过互联网调用远程服务器,不知道远程服务器具体实现,只知道远程服务器提供了什么功能.
RPC
最大优点:数据安全性.
2.2 RPC服务注册/发现过程
简述如下:
- 服务提供者启动时,会将其服务名称,ip地址注册到配置中心。
- 服务消费者在第一次调用服务时,会通过注册中心找到相应的服务的IP地址列表,并缓存到本地,以供后续使用。当消费者调用服务时,不会再去请求注册中心,而是直接通过负载均衡算法从IP列表中取一个服务提供者的服务器调用服务。
- 当服务提供者的某台服务器宕机或下线时,相应的ip会从服务提供者IP列表中移除。同时,注册中心会将新的服务IP地址列表发送给服务消费者机器,缓存在消费者本机。
- 当某个服务的所有服务器都下线了,那么这个服务也就下线了。
- 同样,当服务提供者的某台服务器上线时,注册中心会将新的服务IP地址列表发送给服务消费者机器,缓存在消费者本机。
- 服务提供方可以根据服务消费者的数量来作为服务下线的依据
2.3 设计一个RPC框架需要哪些功能
- 首先我们得需要一个
注册中心
,去管理消费者和提供者的节点信息,这样才会有消费者和提供才可以去订阅服务,注册服务。 - 当有了注册中心后,可能会有很多个
provider
节点,那么我们肯定会有一个负载均衡
模块来负责节点的调用,至于用户指定路由规则可以使一个额外的优化点 - 具体的调用肯定会需要牵扯到
通信协议
,所以需要一个模块来对通信协议进行封装,网络传输还要考虑序列化。 - 当调用失败后怎么去处理?所以我们还需要一个
容错模块
,来负责失败情况的处理。 - 其实做完这些一个基础的模型就已经搭建好了,我们还可以有更多的优化点,比如一些请求数据的监控,配置信息的处理,日志信息的处理等等。
2.4 实例分析
手写一个简单RPC
实例如下
2.4.1 流程图设计
API定义各种服务标准,provider服务提供者,consumer服务消费者
2.4.2 公共接口部分
业务逻辑部分:
方法
public interface UserService {
public UserDTO addUser(UserDTO dto);
}
参数对象 必须实现序列化接口,因为是流化后的对象在网络间传输的
@Data
public class UserDTO implements Serializable {
private static final long serialVersionUID = -7688562483398217382L;
private String userId;
private int age;
private String name;
}
provider和consumer通讯的公共报文定义部分
public class RPCCommonRequestDTO implements Serializable {
private static final long serialVersionUID = -3612648405080153759L;
private String classpath;//类路径
private String methodName;//方法名字
private Object[] params;//参数列表
}
2.4.3 服务提供者
刚进到provider以及服务启动部分
public class ServerAcceptor {
static ExecutorService threadPool= Executors.newFixedThreadPool(10);
public static void startup(int port) throws IOException {
ServerSocket ss = new ServerSocket(port);
while (true) {
Socket socket = ss.accept();//等待客户端连接
threadPool.execute(new Processor(socket));
}
}
public static void main(String[] args) throws IOException {
System.out.println("服务正在启动。。。。。。。。。");
startup(8888);
}
}
服务流化对象读取和写入部分
public class Processor implements Runnable{
private Socket socket;
public Processor(Socket socket) {
this.socket=socket;
}
@Override
public void run() {
try ( ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());){
Object object = ois.readObject();
Object resObject = ServiceDispatch.dispatch(object);
oos.writeObject(resObject);
oos.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}
通过反射处理服务端业务逻辑
public class ServiceDispatch {
/**
* 通过反射机制处理 服务提供 方法
* @param object
* @return
*/
public static Object dispatch(Object object){
RPCCommonRequestDTO dto=(RPCCommonRequestDTO)object;
String classpath = dto.getClasspath();
String methodName = dto.getMethodName();
Object[] params = dto.getParams();
Class[] types =null;
if(params!=null && params.length>0){
types=new Class[params.length];
for(int i=0;i<params.length;i++){
types[i]=params[i].getClass();
}
}
Object resObj=null;
try {
Class<?> clazz = Class.forName(classpath);
Method method = clazz.getDeclaredMethod(methodName, types);
resObj = method.invoke(clazz.newInstance(), params);
} catch (Exception e) {
e.printStackTrace();
}
return resObj;
}
}
服务端业务逻辑部分
public class UserServiceimpl implements UserService {
@Override
public UserDTO addUser(UserDTO dto) {
System.out.println(dto);
dto.setUserId(new Random().nextInt(100000)+"");
dto.setName("haahhah");
dto.setAge(10);
return dto;
}
}
2.4.4 服务消费者
消费者启动以及调用部分
public class CallTest {
public static void main(String[] args) {
UserService userService = InstanceFactory.getUserService(UserService.class);
UserDTO userDTO = new UserDTO();
userDTO= userService.addUser(userDTO);
System.out.println(userDTO);
}
}
消费者网络部分流化处理
public class InstanceFactory {
public static <T> T getUserService(Class<T> clazz){
Object object = Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("RPCInvocationHandler===="+method.getName());
RPCCommonRequestDTO rpc = new RPCCommonRequestDTO();
rpc.setMethodName(method.getName());
rpc.setParams(args);
rpc.setClasspath("cn.jzh.rpc.api.impl.UserServiceimpl");
Object resObj = NetClient.callRemoteService("localhost", 8888, rpc);
return resObj;
}
});
return (T)object;
}
}
消费者网络发送部分
public class NetClient {
public static Object callRemoteService(String host,int port,Object intObj){
Object object = null;
try (Socket socket = new Socket(host, port);
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());){
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
oos.writeObject(intObj);
oos.flush();
object = ois.readObject();
} catch (Exception e) {
e.printStackTrace();
}
return object;
}
}