饿了么开源项目Hermes跨进程架构分析1-服务端注册
文章目录
- 1 注册实现
- 1.1 创建aidl文件
- 1.2 服务端实现
- 1.2.1 HermesService
- 1.2.2 创建Request和Responce
- 1.2.3 创建单例UserManager.java
- 1.2.4 创建数据类Friend.java
- 1.2.5 创建Hermes.java
参考:
https://blog.csdn.net/xiaofei_it/article/details/51464518
https://github.com/Xiaofei-it/Hermes
https://www.jianshu.com/p/29999c1a93cd
链接:
饿了么开源项目Hermes跨进程架构分析1-服务端注册
饿了么开源项目Hermes跨进程架构分析2-客户端连接
先做一个小实验,SecondActivity另启一个进程,代码如下:
public class MyApplication extends Application {private static int i= 0;@Overridepublic void onCreate() {super.onCreate();Log.d("hongxue", "onCreate " + (i++));}}
<activity android:name=".SecondActivity"android:process=":s"/>
输出结果:
hongxue: onCreate 0
hongxue: onCreate 0
i的值并没有增加,说明不同进程间内存不会共享。
首先给出hermes跨进程调用的流程图。
图 hermes跨进程调用
服务端和客户端都会存在一个单例,根据开始的小实验我们知道,不同的进程间内存不共享,所以客户端的是一个单例的动态代理。
在跨进程通信中,如果存在多条数据的发送,就要创建多个aidl文件。为了防止这种情况,hermes对数据进行了再次封装,通过json将对象转化成字符串。
3个步骤:
- 服务端注册
- 客户端连接
- 通信
1 注册实现
1.1 创建aidl文件
先创建aidl文件用于实现进程间通信:
1 MyEventBusService.aidl
import com.hongx.hermes.Request;
import com.hongx.hermes.Responce;
interface MyEventBusService {Responce send(in Request request);
}
2 Responce.aidl
package com.hongx.hermes;
parcelable Responce;
3 Request.aidl
package com.hongx.hermes;
parcelable Request;
1.2 服务端实现
1.2.1 HermesService
需要创建一个 Service 供客户端远程绑定,这里命名为 HermesService。
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;public class HermesService extends Service {@Overridepublic IBinder onBind(Intent intent) {return null;}
}
并在Manifest文件中添加:
<service android:name=".service.HermesService" />
1.2.2 创建Request和Responce
创建Request.java:
import android.os.Parcel;
import android.os.Parcelable;public class Request implements Parcelable {//请求的对象 RequestBean 对应的json字符串private String data;// 请求对象的类型private int type;// 反序列化 A进程protected Request(Parcel in) {data = in.readString();type=in.readInt();}public String getData() {return data;}public int getType() {return type;}public Request(String data, int type) {this.data = data;this.type = type;}public static final Creator<Request> CREATOR = new Creator<Request>() {@Overridepublic Request createFromParcel(Parcel in) {return new Request(in);}@Overridepublic Request[] newArray(int size) {return new Request[size];}};@Overridepublic int describeContents() {return 0;}// 序列化@Overridepublic void writeToParcel(Parcel parcel, int i) {parcel.writeString(data);parcel.writeInt(type);}
}
创建Responce.java:
import android.os.Parcel;
import android.os.Parcelable;public class Responce implements Parcelable {// 响应的对象private String data;public String getData() {return data;}protected Responce(Parcel in) {data = in.readString();}public Responce(String data) {this.data = data;}public static final Creator<Responce> CREATOR = new Creator<Responce>() {@Overridepublic Responce createFromParcel(Parcel in) {return new Responce(in);}@Overridepublic Responce[] newArray(int size) {return new Responce[size];}};@Overridepublic int describeContents() {return 0;}@Overridepublic void writeToParcel(Parcel parcel, int i) {parcel.writeString(data);}
}
注意:要先创建Responce.aidl和Request.aidl ,然后再创建Responce.java 和 Request.java,否则会报错。
1.2.3 创建单例UserManager.java
创建UserManager并注册到服务端,客户端就可以到服务端拿到代理对象。
public class UserManager implements IUserManager {Friend friend;private static UserManager sInstance = null;private UserManager() {}public static synchronized UserManager getInstance(){if(sInstance == null){sInstance = new UserManager();}return sInstance;}public static synchronized UserManager getInstance(String s){if(sInstance == null){sInstance = new UserManager();}return sInstance;}public Friend getFriend() {return friend;}public void setFriend(Friend friend) {this.friend = friend;}public static UserManager getsInstance() {return sInstance;}public static void setsInstance(UserManager sInstance) {UserManager.sInstance = sInstance;}
}
1.2.4 创建数据类Friend.java
public class Friend {private String name;private int age;public Friend(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Friend{" +"name='" + name + '\'' +", age=" + age +'}';}
}
public interface IUserManager {public Friend getFriend();public void setFriend(Friend friend);
}
1.2.5 创建Hermes.java
在MainActivity的onCreate方法中进行初始化和注册
Hermes.getDefault().init(this);Hermes.getDefault().register(UserManager.class);
Hermes.java
public class Hermes {private Context mContext;private TypeCenter typeCenter;private ServiceConnectionManager serviceConnectionManager;private Gson gson = new Gson();//得到对象public static final int TYPE_NEW = 0;//得到单例public static final int TYPE_GET = 1;private static final Hermes ourInstance = new Hermes();public Hermes() {serviceConnectionManager = ServiceConnectionManager.getInstance();typeCenter = TypeCenter.getInstance();}public static Hermes getDefault() {return ourInstance;}public void init(Context context) {this.mContext = context.getApplicationContext();}//----------------------------服务端-------------------------public void register(Class<UserManager> clazz) {typeCenter.register(clazz);}//----------------------------客户端-------------------------public void connect(Context context,Class<HermesService> hermesServiceClass) {connectApp(context, null, hermesServiceClass);}private void connectApp(Context context, String packageName, Class<HermesService> hermesServiceClass) {init(context);serviceConnectionManager.bind(context.getApplicationContext(), packageName, hermesServiceClass);}public <T> T getInstance(Class<T> tClass, Object... parameters) {Responce responce = sendRequest(HermesService.class, tClass, null, parameters);return getProxy(HermesService.class, tClass);}private <T> T getProxy(Class<HermesService> hermesServiceClass, Class<T> tClass) {ClassLoader classLoader = hermesServiceClass.getClassLoader();T proxy = (T) Proxy.newProxyInstance(classLoader, new Class<?>[]{tClass},new HermesInvocationHander(hermesServiceClass, tClass));return proxy;}private <T> Responce sendRequest(Class<HermesService> hermesServiceClass,Class<T> tClass, Method method, Object[] parameters) {RequestBean requestBean = new RequestBean();//set全类名String className = null;if (tClass.getAnnotation(ClassId.class) == null) {requestBean.setClassName(tClass.getName());requestBean.setResultClassName(tClass.getName());} else {requestBean.setClassName(tClass.getAnnotation(ClassId.class).value());requestBean.setResultClassName(tClass.getAnnotation(ClassId.class).value());}//set方法if (method != null) {requestBean.setMethodName(TypeUtils.getMethodId(method));}//set参数RequestParameter[] requestParameters = null;if (parameters != null && parameters.length > 0) {requestParameters = new RequestParameter[parameters.length];for (int i = 0; i < parameters.length; i++) {Object parameter = parameters[i];String parameterClassName = parameter.getClass().getName();String parameterValue = gson.toJson(parameter);RequestParameter requestParameter = new RequestParameter(parameterClassName, parameterValue);requestParameters[i] = requestParameter;}}if (requestParameters != null) {requestBean.setRequestParameter(requestParameters);}Request request = new Request(gson.toJson(requestBean), TYPE_GET);return serviceConnectionManager.request(hermesServiceClass, request);}public <T> Responce sendObjectRequest(Class hermeService, Class<T> aClass,Method method, Object[] args) {RequestBean requestBean = new RequestBean();//set全类名String className = null;if (aClass.getAnnotation(ClassId.class) == null) {requestBean.setClassName(aClass.getName());requestBean.setResultClassName(aClass.getName());} else {requestBean.setClassName(aClass.getAnnotation(ClassId.class).value());requestBean.setResultClassName(aClass.getAnnotation(ClassId.class).value());}//set方法if (method != null) {requestBean.setMethodName(TypeUtils.getMethodId(method));}//set参数RequestParameter[] requestParameters = null;if (args != null && args.length > 0) {requestParameters = new RequestParameter[args.length];for (int i = 0; i < args.length; i++) {Object parameter = args[i];String parameterClassName = parameter.getClass().getName();String parameterValue = gson.toJson(parameter);RequestParameter requestParameter = new RequestParameter(parameterClassName, parameterValue);requestParameters[i] = requestParameter;}}if (requestParameters != null) {requestBean.setRequestParameter(requestParameters);}Request request = new Request(gson.toJson(requestBean), TYPE_NEW);return serviceConnectionManager.request(hermeService, request);}
}
Hermes中定义了初始化、注册等一系列方法,现在我们先看init和register方法,调用Hermes的register方法,最终调用的是TypeCenter的register方法,将UserManager对象保存在一个Map对象中。
TypeCenter.java
public class TypeCenter {//为了减少反射,所以保存起来private final ConcurrentHashMap<Class<?>, ConcurrentHashMap<String, Method>> mRawMethods;private final ConcurrentHashMap<String, Class<?>> mClazz;private static final TypeCenter ourInstance = new TypeCenter();public TypeCenter() {mRawMethods = new ConcurrentHashMap<Class<?>, ConcurrentHashMap<String, Method>>();mClazz = new ConcurrentHashMap<>();}public static TypeCenter getInstance() {return ourInstance;}public void register(Class<HxUserManager> clazz) {//注册--》类, 注册--》方法registerClass(clazz);registerMethod(clazz);}//缓存classprivate void registerClass(Class<HxUserManager> clazz) {String name = clazz.getName();mClazz.putIfAbsent(name, clazz);}private void registerMethod(Class<HxUserManager> clazz) {Method[] methods = clazz.getMethods();for (Method method : methods) {mRawMethods.putIfAbsent(clazz, new ConcurrentHashMap<String, Method>());ConcurrentHashMap<String, Method> map = mRawMethods.get(clazz);String methodId = TypeUtils.getMethodId(method);map.put(methodId, method);}}public Class<?> getClassType(String name) {if (TextUtils.isEmpty(name)) {return null;}Class<?> clazz = mClazz.get(name);if (clazz == null) {try {clazz = Class.forName(name);} catch (ClassNotFoundException e) {e.printStackTrace();}}return clazz;}public Method getMethod(Class<?> aClass, RequestBean requestBean) {String methodName = requestBean.getMethodName();//setFriend()if (methodName != null) {mRawMethods.putIfAbsent(aClass, new ConcurrentHashMap<String, Method>());ConcurrentHashMap<String, Method> methods = mRawMethods.get(aClass);Method method = methods.get(methodName);if(method != null){return method;}int pos = methodName.indexOf('(');Class[] paramters = null;RequestParameter[] requestParameters = requestBean.getRequestParameter();if (requestParameters != null && requestParameters.length > 0) {paramters = new Class[requestParameters.length];for (int i=0;i<requestParameters.length;i++) {paramters[i]=getClassType(requestParameters[i].getParameterClassName());}}method = TypeUtils.getMethod(aClass, methodName.substring(0, pos), paramters);methods.put(methodName, method);return method;}return null;}
}
饿了么开源项目Hermes跨进程架构分析1-服务端注册相关推荐
- 饿了么开源项目Hermes跨进程架构分析2-客户端连接
饿了么开源项目Hermes跨进程架构分析1-服务端注册 饿了么开源项目Hermes跨进程架构分析2-客户端连接 文章目录 2客户端连接 2.1 SecondActivity 2.2 Hermes 2. ...
- 即时通讯(IM)开源项目OpenIM本周版本发布- v1.0.7-web端一键部署
介绍 OpenIM:由前微信技术专家打造的基于 Go 实现的即时通讯(IM)开源项目,包括IM服务端和客户端SDK.开发者私有化部署,基于SDK二次开发,可以轻松替代第三方IM云服务,打造具备聊天.社 ...
- 学习 ET(1)- 开源的游戏客户端(基于 unity3d)服务端双端框架
我: 客户端程序员,15+ 以上 C++ 编码经历, 还算扎实.Unity 编码经历 1年,C# 没有单独学过.真不想离开C++的世界,大形势驱使进入了Unity+C#世界. ET - 开源的游戏客户 ...
- 跨进程访问(AIDL服务)
我们都知道Service的主要的作用是后台运行和跨进程访问. 关于Service后台运行请查看鄙人的另外一篇文章Service基础 本篇博文主要探讨的是跨进程访问~ 什么是AIDL Android系统 ...
- IEC61499开源项目FORTE部分源码分析
一.IEC 61499简介 IEC 61499 作为工业自动化领域分布式控制系统级建模语言的标准,其第一(体系结构).二(软件工具要求).四(兼容文件的规则)部分的第一版于 2005 年正式发布,并在 ...
- Unity开源项目2D流体渲染实现分析
开源项目LiquidEffect渲染分析 项目传送门 实现流程 步骤一 创建刚体 步骤二 降采样与模糊处理 降采样分析 C#部分 顶点着色器 片元着色器 分析 模糊分析 步骤三 Alpha过滤 项目传 ...
- 基于eBPF技术的开源项目Kindling之探针架构介绍
Kindling开源项目是一款基于eBPF技术的云原生可观测性项目.本文将主要介绍探针的具体架构设计. Kindling探针的架构设计理念 Kindling架构设计中有一个很重要的理念:关注点分离(S ...
- vue.js+koa2项目实战(四)搭建koa2服务端
搭建koa2服务端 安装两个版本的koa 一.版本安装 1.安装 koa1 npm install koa -g 注:必须安装到全局 2.安装 koa2 npm install koa@2 -g 二. ...
- mysql第五章项目二_Todo List:Node+Express 搭建服务端毗邻Mysql – 第五章(第1节)
点击右上方红色按钮关注"web秀",让你真正秀起来 前言 万丈高楼平地起,我们的Todo List项目也是越来越结实了.Todo List的前面4章内容都是在为Client端开发, ...
最新文章
- 开源仓库Harbor搭建及配置过程
- 简单计算机病毒黑屏,教大家一个黑屏小程序
- 下列关于linux的进程,描述不正确的是,进程是资源管理的最小单位,2012年7月成人自考网络操作系统考试真题...
- 【团队管理】改造团队成员?
- VC ADO连接ACCESS步骤及错误处理
- C#经典名著:《C#入门经典》(第4版)
- 关于NSArray使用时用strong修饰还是copy修饰问题测试
- init进程 解析Android启动脚本init.rc 修改它使不启动android init.rc中启动一个sh文件...
- 无法直接打开jar文件,提示“你要以何种方式打开.jar文件”(已解决)
- SQLServer 数据库无法重命名
- 金仓数据库在 TPCE(dbt5,tpsE)测试框架方面的实践和突破
- asp.net摄影网站系统VS开发sqlserver数据库web结构c#编程计算机网页源码项目
- 操作系统简史(1)东方会有新的操作系统诞生吗?让历史告诉未来
- 第十四届蓝桥杯模拟赛(Python)
- 【Android】使用MediaExtractor、MediaMuxer去掉视频文件中的音频数据
- 手抛飞机大改装(4种机型,7种改法)干货!!
- 关于scene understanding场景理解概念的理解
- 王者农药新模式——智慧王者 树形递归
- 安排,全栈分布式微服务媒资管理系统(视频、代码)
- POJ3014(最小覆盖点;匈牙利算法)
热门文章
- 小米OPPO适配鸿蒙系统,以后oppo或者vivo以及小米有没有机会用使用华为鸿蒙系统?...
- i5 10400F和i5 10600K哪个性价比高
- 树莓派(raspbian)如何消除屏幕右上角“闪电”符号
- html+css实现横向时间线
- kolla安装(1)
- 概率论与数理统计 浙江大学 第44-53讲单元测验
- jquery实现ajax异步请求
- goland如何修改背景为图片
- python实现一个个人名片复杂一点,给出制作思路,使用面向对象的方法
- 易语言反截图_[搬运]反截图技术的原理及简单实现