天天看点

饿了么开源项目Hermes跨进程架构分析1-服务端注册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;
    @Override
    public 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跨进程架构分析1-服务端注册1 注册实现

图 hermes跨进程调用

  1. 服务端和客户端都会存在一个单例,根据开始的小实验我们知道,不同的进程间内存不共享,所以客户端的是一个单例的动态代理。
  2. 在跨进程通信中,如果存在多条数据的发送,就要创建多个aidl文件。为了防止这种情况,hermes对数据进行了再次封装,通过json将对象转化成字符串。

3个步骤:

  1. 服务端注册
  2. 客户端连接
  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 {
    
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

           

并在Manifest文件中添加:

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>() {
        @Override
        public Request createFromParcel(Parcel in) {
            return new Request(in);
        }
        @Override
        public Request[] newArray(int size) {
            return new Request[size];
        }
    };
    @Override
    public int describeContents() {
        return 0;
    }
    //  序列化
    @Override
    public 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>() {
        @Override
        public Responce createFromParcel(Parcel in) {
            return new Responce(in);
        }
        @Override
        public Responce[] newArray(int size) {
            return new Responce[size];
        }
    };
    @Override
    public int describeContents() {
        return 0;
    }
    @Override
    public 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;
    }
    @Override
    public 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);
    }

    //缓存class
    private 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;
    }
}