在实际的开发中,bus 的使用还是比较多的,对于模块化路由的使用 ,还有模块之间的通讯,于Ctrip 目前项目中的使用,主要是存在2种bus,一种是Ctrip 自己封装的bus 还有一种是使用了开源的EventBus 我们分别来看下他们的实现方式
1 在App 启动的时候,会对bus 进行初始化的配置:
static void intBusAndBundle(Application application) {
BusInit busInit = new BusInit();
//bus manager init
BusManager.init(busInit);
//all bundles setted
configBundles();
//BundleCore init
try {
BundleCore.getInstance().init(application);
} catch (Exception ex) {
ex.printStackTrace();
}
}
我们看到这个里有BusInit 的类,在程序启动的时候,创建了busInit 的实例,我们看下,该方法中的实际实现:
它实现了 BusObjectProvider
public interface BusObjectProvider {
boolean register(BusObject var1);
BusObject findBusObject(String var1);
void asyncFindBusObject(Context var1, String var2, AsyncBusObjectCallback var3);
}
看看里面的具体实现方法:
public class BusInit implements BusObjectProvider {
private static final Map<String, BusObject> hostMap = new HashMap<>();
private static final Map<String, LoadBusObjectRunnable> hostRunnableMap = new HashMap<>();
@Override
public boolean register(BusObject busObject) {
if (busObject == null) {
LogUtil.d("Bus", "register BusObject error:" + busObject);
return false;
}
String host = busObject.getHost().toLowerCase();
if (hostMap.containsKey(host)) {
LogUtil.d("Bus", host + " :已注册,不可重复注册");
} else {
busObject.troogleBundleCreated();
LogUtil.d("Bus", "troogleBundleCreated on register:" + busObject.getHost() + ", pid:" + Process.myPid());
}
hostMap.put(host, busObject);
return true;
}
@Override
public BusObject findBusObject(String host) {
if (TextUtils.isEmpty(host)) {
return null;
}
// 同步Load
BusObject obj = hostMap.get(host.toLowerCase());
if (obj == null) {
obj = getBusObjectRunnable(host).doLoad();
if (obj != null) {
hostMap.put(host.toLowerCase(), obj);
}
LogUtil.d("Bus", "findBusObject inner:" + host + "," + obj);
}
return obj;
}
private void asyncFindLocalBusObject(final String host, final BusManager.AsyncBusObjectCallback asyncBusObjectCallback) {
if (TextUtils.isEmpty(host)) {
if (asyncBusObjectCallback != null) {
asyncBusObjectCallback.onFindBusObject(null);
}
}
BusObject obj = hostMap.get(host.toLowerCase());
if (obj == null) {
String savedHost = host.toLowerCase();
LoadBusObjectRunnable loadBusObjectRunnable = getBusObjectRunnable(savedHost);
loadBusObjectRunnable.addBusObjectCallback(asyncBusObjectCallback);
if (!loadBusObjectRunnable.isRunning()) {
ThreadUtils.runOnBackgroundThread(loadBusObjectRunnable);
}
} else {
if (asyncBusObjectCallback != null) {
asyncBusObjectCallback.onFindBusObject(obj);
}
}
}
private LoadBusObjectRunnable getBusObjectRunnable(String host) {
if (TextUtils.isEmpty(host)) {
return null;
}
String savedHost = host.toLowerCase();
LoadBusObjectRunnable loadBusObjectRunnable = hostRunnableMap.get(savedHost);
if (loadBusObjectRunnable == null) {
LogUtil.d("BusLoad", "getBusObjectRunnable is null, new Runnable");
loadBusObjectRunnable = new LoadBusObjectRunnable(savedHost);
hostRunnableMap.put(savedHost, loadBusObjectRunnable);
}
return loadBusObjectRunnable;
}
@Override
public void asyncFindBusObject(final Context context, final String hostName, final BusManager.AsyncBusObjectCallback busObjectCallback) {
final BundleConfigModel bundleConfigModel = BundleConfigFactory.getBundleConfigModelByModuleName(hostName);
if (bundleConfigModel != null) {
if (Package.isMCDPackage() && bundleConfigModel.bundleLoadType == BundleConfigModel.BundleLoadType.RemoteLoad) {
if (!BundleFacade.isRemotePackageInstall(bundleConfigModel.packageName)) {
LogUtil.e("RemotePackageNotInstall");
PluginLoaderManager.getInstance().downLoadPlugin(context, bundleConfigModel.packageName, PluginLoaderManager.LOAD_TYPE_FOREGROUND,new PluginLoaderListener() {
@Override
public void onDownloadSize(int size, int totalSize) {
LogUtil.e("remote bundle download:size change-" + size + "," + totalSize);
}
@Override
public void onDownloadSucess() {
LogUtil.e("remote bundle download:onDownloadSucess");
BusObject obj = findBusObject(hostName);
if (obj != null && busObjectCallback != null) {
busObjectCallback.onFindBusObject(obj);
}
}
@Override
public void onDownLoadFail() {
LogUtil.e("remote bundle download:onDownLoadFail");
}
@Override
public boolean install(String filePath) {
LogUtil.e("remote bundle download:install-" + filePath);
return BundleFacade.remoteLoadInstall(bundleConfigModel.packageName, filePath);
}
});
} else {
if (PluginLoaderManager.getInstance().hasNewVersionForPlugin(bundleConfigModel.packageName)) {
LogUtil.e("hasNewVersionForPlugin");
PluginLoaderManager.getInstance().downLoadPlugin(context, bundleConfigModel.packageName, PluginLoaderManager.LOAD_TYPE_FOREGROUND,new PluginLoaderListener() {
@Override
public void onDownloadSize(int size, int totalSize) {
}
@Override
public void onDownloadSucess() {
BusObject obj = findBusObject(hostName);
if (obj != null && busObjectCallback != null) {
busObjectCallback.onFindBusObject(obj);
}
}
@Override
public void onDownLoadFail() {
}
@Override
public boolean install(String filePath) {
return BundleFacade.remoteLoadUpgrade(bundleConfigModel.packageName,filePath);
}
});
}else {
BusObject obj = findBusObject(hostName);
if (obj != null && busObjectCallback != null) {
LogUtil.e("have not NewVersionForPlugin--busObjectCallback");
busObjectCallback.onFindBusObject(obj);
}
}
}
} else {
asyncFindLocalBusObject(hostName, new BusManager.AsyncBusObjectCallback() {
@Override
public void onFindBusObject(BusObject busObject) {
if (busObject != null && busObjectCallback != null) {
LogUtil.e("RemotePackageInstall--busObjectCallback:" + busObject + "," + busObjectCallback);
busObjectCallback.onFindBusObject(busObject);
}
}
});
}
}
}
}
我们看到该类中提供了 register 和 findBusObject 两个方法,Bus 的bus 的维持方式,在
Map<String, BusObject> hostMap = new HashMap<>();
我们看到方法
@Override
public BusObject findBusObject(String host) {
if (TextUtils.isEmpty(host)) {
return null;
}
// 同步Load
BusObject obj = hostMap.get(host.toLowerCase());
if (obj == null) {
obj = getBusObjectRunnable(host).doLoad();
if (obj != null) {
hostMap.put(host.toLowerCase(), obj);
}
LogUtil.d("Bus", "findBusObject inner:" + host + "," + obj);
}
return obj;
}
是寻找Bus 如果要寻找的Bus 不存在,则执行
obj = getBusObjectRunnable(host).doLoad();
我们看下这个代码中的具体实现:
private LoadBusObjectRunnable getBusObjectRunnable(String host) {
if (TextUtils.isEmpty(host)) {
return null;
}
String savedHost = host.toLowerCase();
LoadBusObjectRunnable loadBusObjectRunnable = hostRunnableMap.get(savedHost);
if (loadBusObjectRunnable == null) {
LogUtil.d("BusLoad", "getBusObjectRunnable is null, new Runnable");
loadBusObjectRunnable = new LoadBusObjectRunnable(savedHost);
hostRunnableMap.put(savedHost, loadBusObjectRunnable);
}
return loadBusObjectRunnable;
}
可以看出是个 LoadBusObjectRunnable 对象,再看后面的 load() 的方法实现
public BusObject doLoad() {
isRunning = true;
BusObject busObject = registerBusObjectWithHost(hostName);
isRunning = false;
actionCallback(busObject);
return busObject;
}
我们看到,这里如果是注册 registerBusObjectWithHost(hostName) 这个方法的实现过程,具体分析看源码
private BusObject registerBusObjectWithHost(String hostName) {
Tick.start("registerBusObjectWithHost:" + hostName);
try {
if (StringUtil.isEmpty(hostName)) {
return null;
}
BusObject retObj = null;
if (COMMON_HOST_NAME.equalsIgnoreCase(hostName)) {
// 这里是用 公共带有common 库
try {
Class<BusObject> clazz = (Class<BusObject>) Class.forName(COMMON_BUS_OBJECT);
Constructor<BusObject> constructor = clazz.getConstructor(String.class); //动态获取构造函数
BusObject tmpRetObj = constructor.newInstance(hostName);
if (Bus.register(tmpRetObj)) {//注册这个object
return tmpRetObj;
}
} catch (Exception e) {
e.printStackTrace();
}
// 这里是rn 的BusObject
} else if(REACT_NATIVE_Host_Name.equalsIgnoreCase(hostName)) {
try {
Class<BusObject> clazz = (Class<BusObject>) Class.forName(REACT_NATIVE_BUS_OBJECT);
Constructor<BusObject> constructor = clazz.getConstructor(String.class);//动态获取构造函数
BusObject tmpRetObj = constructor.newInstance(hostName);
if (Bus.register(tmpRetObj)) {//注册这个object
return tmpRetObj;
}
} catch (Exception e) {
e.printStackTrace();
}
}
// 这里是常规的bundle 的方式,首先先验证下所要寻找的bundle包是不是在注册的里,如果不在注册里,返回位null
BundleConfigModel bundleConfigModel = BundleConfigFactory.getBundleConfigModelByModuleName(hostName);
if (null == bundleConfigModel) {
LogUtil.f("BusManager", "getBundleConfigModelByModuleName bundleConfigModel is null :" + bundleConfigModel + "," + hostName);
return null;
}
// 在注册中返回busObjectName,根据bundle 的加载方式,执行不同的策略
String className = bundleConfigModel.busObjectName;
if (!StringUtil.isEmpty(className)) {
LogUtil.d("BusManager", "BusManager执行:" + className);
try {
String packageName = bundleConfigModel.packageName;
if (!TextUtils.isEmpty(packageName)) {
if (bundleConfigModel.bundleLoadType == BundleConfigModel.BundleLoadType.RemoteLoad) {
if (!BundleFacade.isRemotePackageInstall(packageName)) {
LogUtil.d("BusManager", "Remoting Load must call asyncCall method");
}
} else {
// 先注入依赖的bundle,加载所依赖的bundle 包
if (bundleConfigModel.dependenceList != null) {
for(String depBundleName : bundleConfigModel.dependenceList) {
BundleConfigModel model = BundleConfigFactory.getBundleConfigModelByModuleName(depBundleName);
if (model != null) {
BundleFacade.delayLoadInstall(model.packageName);
}
}
}
// 注入当前bundle
BundleFacade.delayLoadInstall(packageName);
}
}
// 动态的注入相应的Class
Class<BusObject> clazz = (Class<BusObject>) Class.forName(className);
Constructor<BusObject> constructor = clazz.getConstructor(String.class); //动态获取构造函数
BusObject tmpRetObj = constructor.newInstance(hostName);
if (Bus.register(tmpRetObj)) {//注册这个object
retObj = tmpRetObj;
}
} catch (Exception e) {
LogUtil.d("BusManager", "create BusObject error:" + e.getMessage());
e.printStackTrace();
String model = bundleConfigModel.packageName;
String logd = ctrip.foundation.util.StringUtil.getDescriptionFromException(e);
if (!Env.isTestEnv()) {
LogUtil.f("BusManager", "BusManager error:" + logd);
}
if (!TextUtils.isEmpty(model) && !bundleLogWhiteList.contains(model)) {
try {
int result = BundleCore.getInstance().ValidBundle(model);
Map dic = new HashMap();
dic.put("hostName", hostName);
dic.put("type", result);
dic.put("error", logd);
CtripActionLogUtil.logTrace("o_bus_register_error", dic);
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
}
return retObj;
} finally {
Tick.end();
}
}
我们看到这个是个系统的Bus 的 注册管理,最终系统的调用是在Bus 的类中使用,我们看下代码中具体实现
public class Bus {
/**
* 注册业务对象到总线
*
* @param busObject 处理业务job的对象
* @throws IllegalArgumentException 如果host已被注册,抛出异常不可重复注册
*/
public synchronized static boolean register(BusObject busObject) {
return BusManager.register(busObject);
}
/**
* 查找业务总线
*/
public static BusObject findBusObject(String bizName) {
return BusManager.findBusObject(bizName);
}
/**
* 数据总线,跨业务模块异步调用
*
* @param context 调用上下文。根据调用场景自行决定,常见可选值null/Application/Activity等
* @param bizName 业务接口名,大小写不敏感
* @param resultListener 业务job处理完成回调数据
* @param param 附加参数列表
*/
public static void asyncCallData(final Context context, final String bizName, final BusObject.AsyncCallResultListener resultListener, final Object... param) {
BusManager.asyncFindBusObject(context, BusManager.parseBizNameHost(bizName), new BusManager.AsyncBusObjectCallback() {
@Override
public void onFindBusObject(BusObject busObject) {
if (busObject != null) {
busObject.doAsyncDataJob(context, bizName, resultListener, param);
}
}
});
}
/**
* 数据总线,跨业务模块同步调用
*
* @param context 调用上下文。根据调用场景自行决定,常见可选值null/Application/Activity等
* @param bizName 业务接口名,大小写不敏感
* @param param 附加参数
* @return 直接返回对方接口的返回值
*/
public static Object callData(Context context, String bizName, Object... param) {
LogUtil.d("JTIME", "callData:" + bizName);
try {
BusObject obj = BusManager.findBusObject(BusManager.parseBizNameHost(bizName));
if (obj != null) {
return obj.doDataJob(context, bizName, param);
} else {
HashMap<String, String> info = new HashMap<>();
info.put("bizName", bizName);
StringBuilder params = new StringBuilder();
if (param != null && param.length > 0) {
for(Object p : param) {
params.append(p == null ? "null" : p.getClass() + ":" + p);
}
}
info.put("params", params.toString());
LogUtil.logMetrics("o_bus_calldata_not_found", 0, info);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 数据总线,跨业务模块异步调用
* 寻找BusObject的过程在异步完成,将会触发 callData(用来解决首次bundle异步加载callBus耗时问题)
*/
public static void callDataOnBackground(final Context context, final String bizName, final BusObject.AsyncCallResultListener resultListener, final Object... param) {
LogUtil.d("Bus", "callDataOnBackground:" + bizName + "," + resultListener);
BusManager.asyncFindBusObject(context, BusManager.parseBizNameHost(bizName), new BusManager.AsyncBusObjectCallback() {
@Override
public void onFindBusObject(final BusObject busObject) {
LogUtil.d("Bus", "callDataOnBackground callback:" + bizName + "," + busObject);
if (busObject != null) {
ThreadUtils.post(new Runnable() {
@Override
public void run() {
Object data = busObject.doDataJob(context, bizName, param);
if (resultListener != null) {
resultListener.asyncCallResult("", data);
}
}
});
}
}
});
}
/**
* URL总线,跨业务模块异步调用(不建议使用)
*
* @param context 调用上下文。根据调用场景自行决定,常见可选值null/Application/Activity等
* @param url 业务url,大小写不敏感
* @param resultListener 业务job处理完成回调数据
*/
public static void asyncCallURL(Context context, String url, BusObject.AsyncCallResultListener resultListener) {
BusObject obj = BusManager.findBusObject(BusManager.parseUrlHost(url));
if (obj != null) {
obj.doAsyncURLJob(context, url, resultListener);
}
}
/**
* URL总线,跨业务模块同步调用
*
* @param context 调用上下文。根据调用场景自行决定,常见可选值null/Application/Activity等
* @param url 业务url,大小写不敏感
* @return 直接返回对方接口的返回值
*/
public static Object callURL(Context context, String url) {
BusObject obj = BusManager.findBusObject(BusManager.parseUrlHost(url));
if (obj != null) {
return obj.doURLJob(context, url);
}
return null;
}
}
我们看到CallData 的方法中,的方法调用了方法
BusObject obj = BusManager.findBusObject(BusManager.parseBizNameHost(bizName));
那我看下 BusManager 的findBusObject 中具体实现方式
static BusObject findBusObject(String hostName) {
return busObjectProvider.findBusObject(hostName);
}
我们看到,最终会调到上面分析的 busObjectProvider.findBusObject(hostName); 最终是调用到我们上面分析的代码。
2 开源框架 EventBus
我们先看下EventBus 是如何初始化的
/** Convenience singleton for apps using a process-wide EventBus instance. */
public static EventBus getDefault() {
EventBus instance = defaultInstance;
if (instance == null) {
synchronized (EventBus.class) {
instance = EventBus.defaultInstance;
if (instance == null) {
instance = EventBus.defaultInstance = new EventBus();
}
}
}
return instance;
}
我们看下EventBus 是通过构造器的方式去传达
/**
* Creates a new EventBus instance; each instance is a separate scope in which events are delivered. To use a
* central bus, consider {@link #getDefault()}.
*/
public EventBus() {
this(DEFAULT_BUILDER);
}
EventBus(EventBusBuilder builder) {
logger = builder.getLogger();
subscriptionsByEventType = new HashMap<>();
typesBySubscriber = new HashMap<>();
stickyEvents = new ConcurrentHashMap<>();
mainThreadSupport = builder.getMainThreadSupport();
mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
// 事件background 处理
backgroundPoster = new BackgroundPoster(this);
asyncPoster = new AsyncPoster(this);
indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex);
logSubscriberExceptions = builder.logSubscriberExceptions;
logNoSubscriberMessages = builder.logNoSubscriberMessages;
sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
throwSubscriberException = builder.throwSubscriberException;
eventInheritance = builder.eventInheritance;
executorService = builder.executorService;
}
我们看下源码注册过程
/**
* Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
* are no longer interested in receiving events.
* <p/>
* Subscribers have event handling methods that must be annotated by {@link Subscribe}.
* The {@link Subscribe} annotation also allows configuration like {@link
* ThreadMode} and priority.
*/
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
//通过subscriberMethodFinder 返回一个List ,包含method对象以及将来相应订阅再那个线程的mode 时间的enventType 和 优先级
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
我们来一起看看 findSubscriberMethods 方法中的实现方式
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
if (ignoreGeneratedIndex) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
subscriberMethods = findUsingInfo(subscriberClass);
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
我们来看下subscirbe 的实现方式,分享看源码
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
int size = subscriptions.size();
for (int i = 0; i <= size; i++) {
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
if (subscriberMethod.sticky) {
if (eventInheritance) {
// Existing sticky events of all subclasses of eventType have to be considered.
// Note: Iterating over all events may be inefficient with lots of sticky events,
// thus data structure should be changed to allow a more efficient lookup
// (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).
Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
for (Map.Entry<Class<?>, Object> entry : entries) {
Class<?> candidateEventType = entry.getKey();
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}