前言
Android无论App开发还是SDK开发,都绕不开组件化,组件化要解决的最大的问题就是组件之间的通信,即路由框架。国内使用最多的两个路由框架一个是阿里的ARouter,另一个是美团的WMRouter。这两个路由框架功能都很强大,笔者都有使用过。从源码上来看,WMRouter的架构更加清晰,可读性更强。从扩展性来讲,WMRouter更灵活,且具备很强大的无侵入式扩展性。这两个框架都使用了Android开发当中比较前沿的技术,一个是APT技术,一个是字节码插桩技术。WMRouter与Arouter最大的不同是它使用了自定义的ServiceLoader,这个ServiceLoader就是用来加载各个子工程中的服务。今天笔者就挑WMRouter来讲一讲它的实现过程。
本文基于WMRouter源码的1.2.1版本。
笔者原创,转载请注明出处:https://blog.csdn.net/devnn/article/details/136969237
WMRouter的设计与使用文档
关于WMRouter的使用还不了解,可以去githup看一看。先对它有一个整体的认识。
WMRouter设计与使用文档
简单来说,使用分为4步:
1、在Gradle中引入依赖、添加插件
2、初始化
// 创建RootHandler
val rootHandler = DefaultRootUriHandler(this)
// 初始化
Router.init(rootHandler)
3、配置路由
@RouterUri(scheme = "aaa", host = "bbb", path = ["/page1"])
class ActivityTest1 : AppCompatActivity() {
...
}
4、跳转
Router.startUri(context, "aaa://bbb/page1");
WMRouter源码解析
WMRouter初始化
使用WMRouer之前先要初始化,看一下初始化代码
//com.sankuai.waimai.router.Router
public class Router {
@SuppressLint("StaticFieldLeak")
private static RootUriHandler ROOT_HANDLER;
/**
* 此初始化方法必须在主线程调用。
*/
public static void init(@NonNull RootUriHandler rootUriHandler) {
if (!Debugger.isLogSetting()) {
Log.w(Debugger.LOG_TAG, "!!当前未设置Logger,建议通过 Debugger.setLogger()方法设置Logger");
Log.w(Debugger.LOG_TAG, "!!并在测试环境通过 Debugger.EnableLog(true)方法开启日志");
Log.w(Debugger.LOG_TAG, "!!通过Debugger.setEnableDebug(true)方法在测试环境及时抛出严重类型异常");
}
if (Looper.myLooper() != Looper.getMainLooper()) {
Debugger.fatal("初始化方法init应该在主线程调用");
}
if (ROOT_HANDLER == null) {
ROOT_HANDLER = rootUriHandler;
} else {
Debugger.fatal("请勿重复初始化UriRouter");
}
}
/**
* 此初始化方法的调用不是必须的。
* 使用时会按需初始化;但也可以提前调用并初始化,使用时会等待初始化完成。
* 本方法线程安全。
*/
public static void lazyInit() {
ServiceLoader.lazyInit();
getRootHandler().lazyInit();
}
public static RootUriHandler getRootHandler() {
if (ROOT_HANDLER == null) {
throw new RuntimeException("请先调用init初始化UriRouter");
}
return ROOT_HANDLER;
}
public static void startUri(UriRequest request) {
getRootHandler().startUri(request);
}
public static void startUri(Context context, String uri) {
getRootHandler().startUri(new UriRequest(context, uri));
}
//省略无关代码
}
可以看到,初始化主要是给ROOT_HANDLER
赋值,调用startUri
方法跳转时,也是委托给了初始化传入的RootUriHandler
。
接下来看看初始化传入的DefaultRootUriHandler
:
package com.sankuai.waimai.router.common;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.sankuai.waimai.router.annotation.RouterUri;
import com.sankuai.waimai.router.components.DefaultOnCompleteListener;
import com.sankuai.waimai.router.core.RootUriHandler;
import com.sankuai.waimai.router.regex.RegexAnnotationHandler;
import com.sankuai.waimai.router.utils.LazyInitHelper;
/**
* 默认的RootHandler实现
*
* Created by jzj on 2018/3/23.
*/
public class DefaultRootUriHandler extends RootUriHandler {
private final PageAnnotationHandler mPageAnnotationHandler;
private final UriAnnotationHandler mUriAnnotationHandler;
private final RegexAnnotationHandler mRegexAnnotationHandler;
public DefaultRootUriHandler(Context context) {
this(context, null, null);
}
/**
* @param defaultScheme {@link RouterUri} 没有指定scheme时,则使用这里设置的defaultScheme
* @param defaultHost {@link RouterUri} 没有指定host时,则使用这里设置的defaultHost
*/
public DefaultRootUriHandler(Context context,
@Nullable String defaultScheme, @Nullable String defaultHost) {
super(context);
mPageAnnotationHandler = createPageAnnotationHandler();
mUriAnnotationHandler = createUriAnnotationHandler(defaultScheme, defaultHost);
mRegexAnnotationHandler = createRegexAnnotationHandler();
// 按优先级排序,数字越大越先执行
// 处理RouterPage注解定义的内部页面跳转,如果注解没定义,直接结束分发
addChildHandler(mPageAnnotationHandler, 300);
// 处理RouterUri注解定义的URI跳转,如果注解没定义,继续分发到后面的Handler
addChildHandler(mUriAnnotationHandler, 200);
// 处理RouterRegex注解定义的正则匹配
addChildHandler(mRegexAnnotationHandler, 100);
// 添加其他用户自定义Handler...
// 都没有处理,则尝试使用默认的StartUriHandler直接启动Uri
addChildHandler(new StartUriHandler(), -100);
// 全局OnCompleteListener,用于输出跳转失败提示信息
setGlobalOnCompleteListener(DefaultOnCompleteListener.INSTANCE);
}
/**
* @see LazyInitHelper#lazyInit()
*/
public void lazyInit() {
mPageAnnotationHandler.lazyInit();
mUriAnnotationHandler.lazyInit();
mRegexAnnotationHandler.lazyInit();
}
public PageAnnotationHandler getPageAnnotationHandler() {
return mPageAnnotationHandler;
}
public UriAnnotationHandler getUriAnnotationHandler() {
return mUriAnnotationHandler;
}
public RegexAnnotationHandler getRegexAnnotationHandler() {
return mRegexAnnotationHandler;
}
@NonNull
protected PageAnnotationHandler createPageAnnotationHandler() {
return new PageAnnotationHandler();
}
@NonNull
protected UriAnnotationHandler createUriAnnotationHandler(@Nullable String defaultScheme,
@Nullable String defaultHost) {
return new UriAnnotationHandler(defaultScheme, defaultHost);
}
@NonNull
protected RegexAnnotationHandler createRegexAnnotationHandler() {
return new RegexAnnotationHandler();
}
}
RootUriHandler采用了责任链的设计模式,它是ChainedHandler
的子类:
public class RootUriHandler extends ChainedHandler {
//代码略,主要是一个责任链模式,建议参阅源码。这个不是本文重点。
}
因此DefaultRootUriHandler
只是一个壳,实际业务交给了责任链中的处理器。
回到DefaultRootUriHandler
,可以看到在它的构造方法中添加了责任链的节点(或叫处理器),因此路由的跳转请求交给了这些处理器。
可以看到,一共添加了4个处理器,分别是mPageAnnotationHandler
、mUriAnnotationHandler
、mRegexAnnotationHandler
、new StartUriHandler()
。
mPageAnnotationHandler
是用来兼容老的跳转方式,它跟mUriAnnotationHandler
是区别是,前者的scheme和host是固定的,即wm_router:\\page
,后者的scheme和host支持可配也支持空(不配的情况下默认是空)。
mUriAnnotationHandler
用来处理一般的Uri跳转。
mRegexAnnotationHandler
是用来匹配正则表达式的路由跳转。
StartUriHandler
是用来兜底的处理器。
大多数情况下,使用的是mUriAnnotationHandler
这个Uri处理器。
UriAnnotationHandler处理Uri请求
接下来,我们关注mUriAnnotationHandler
代码,它的类型是UriAnnotationHandler
:
package com.sankuai.waimai.router.common;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.text.TextUtils;
import com.sankuai.waimai.router.annotation.RouterUri;
import com.sankuai.waimai.router.components.RouterComponents;
import com.sankuai.waimai.router.core.UriCallback;
import com.sankuai.waimai.router.core.UriHandler;
import com.sankuai.waimai.router.core.UriInterceptor;
import com.sankuai.waimai.router.core.UriRequest;
import com.sankuai.waimai.router.utils.LazyInitHelper;
import com.sankuai.waimai.router.utils.RouterUtils;
import java.util.HashMap;
import java.util.Map;
/**
* URI跳转,通过注解 {@link RouterUri} 配置,可处理多个Scheme+Host。
*
* 接收到 {@link UriRequest} 时, {@link UriAnnotationHandler} 根据scheme+host产生的key,
* 分发给对应的 {@link PathHandler},{@link PathHandler} 再根据path分发给每个子节点。
*
* Created by jzj on 2018/3/23.
*/
public class UriAnnotationHandler extends UriHandler {
private static boolean sAddNotFoundHandler = true;
/**
* 设置是否在每个PathHandler上添加一个NotFoundHandler,默认为true。
* 如果添加了NotFoundHandler,则只要scheme+host匹配上,所有的URI都会被PathHandler拦截掉,
* 即使path不能匹配,也会分发到NotFoundHandler终止分发。
*/
public static void setAddNotFoundHandler(boolean addNotFoundHandler) {
sAddNotFoundHandler = addNotFoundHandler;
}
/**
* key是由scheme+host生成的字符串,value是PathHandler。
*/
private final Map<String, PathHandler> mMap = new HashMap<>();
/**
* {@link RouterUri} 没有指定scheme时,则使用这里设置的defaultScheme
*/
private final String mDefaultScheme;
/**
* {@link RouterUri} 没有指定host时,则使用这里设置的defaultHost
*/
private final String mDefaultHost;
private final LazyInitHelper mInitHelper = new LazyInitHelper("UriAnnotationHandler") {
@Override
protected void doInit() {
initAnnotationConfig();
}
};
/**
* @param defaultScheme {@link RouterUri} 没有指定scheme时,则使用这里设置的defaultScheme
* @param defaultHost {@link RouterUri} 没有指定host时,则使用这里设置的defaultHost
*/
public UriAnnotationHandler(@Nullable String defaultScheme, @Nullable String defaultHost) {
mDefaultScheme = RouterUtils.toNonNullString(defaultScheme);
mDefaultHost = RouterUtils.toNonNullString(defaultHost);
}
/**
* @see LazyInitHelper#lazyInit()
*/
public void lazyInit() {
mInitHelper.lazyInit();
}
protected void initAnnotationConfig() {
RouterComponents.loadAnnotation(this, IUriAnnotationInit.class);
}
public PathHandler getPathHandler(String scheme, String host) {
return mMap.get(RouterUtils.schemeHost(scheme, host));
}
/**
* 给指定scheme和host的节点设置path前缀
*/
public void setPathPrefix(String scheme, String host, String prefix) {
PathHandler pathHandler = getPathHandler(scheme, host);
if (pathHandler != null) {
pathHandler.setPathPrefix(prefix);
}
}
/**
* 给所有节点设置path前缀
*/
public void setPathPrefix(String prefix) {
for (PathHandler pathHandler : mMap.values()) {
pathHandler.setPathPrefix(prefix);
}
}
public void register(String scheme, String host, String path,
Object handler, boolean exported, UriInterceptor... interceptors) {
// 没配的scheme和host使用默认值
if (TextUtils.isEmpty(scheme)) {
scheme = mDefaultScheme;
}
if (TextUtils.isEmpty(host)) {
host = mDefaultHost;
}
String schemeHost = RouterUtils.schemeHost(scheme, host);
PathHandler pathHandler = mMap.get(schemeHost);
if (pathHandler == null) {
pathHandler = createPathHandler();
mMap.put(schemeHost, pathHandler);
}
pathHandler.register(path, handler, exported, interceptors);
}
@NonNull
protected PathHandler createPathHandler() {
PathHandler pathHandler = new PathHandler();
if (sAddNotFoundHandler) {
pathHandler.setDefaultChildHandler(NotFoundHandler.INSTANCE);
}
return pathHandler;
}
/**
* 通过scheme+host找对应的PathHandler,找到了才会处理
*/
private PathHandler getChild(@NonNull UriRequest request) {
return mMap.get(request.schemeHost());
}
@Override
public void handle(@NonNull UriRequest request, @NonNull UriCallback callback) {
mInitHelper.ensureInit();
super.handle(request, callback);
}
@Override
protected boolean shouldHandle(@NonNull UriRequest request) {
return getChild(request) != null;
}
@Override
protected void handleInternal(@NonNull UriRequest request, @NonNull UriCallback callback) {
PathHandler pathHandler = getChild(request);
if (pathHandler != null) {
pathHandler.handle(request, callback);
} else {
// 没找到的继续分发
callback.onNext();
}
}
@Override
public String toString() {
return "UriAnnotationHandler";
}
}
可以看到它的handle
方法中,首先调用了 mInitHelper.ensureInit()
,用来确保路由组件已经注册:
//com.sankuai.waimai.router.common.UriAnnotationHandler
@Override
public void handle(@NonNull UriRequest request, @NonNull UriCallback callback) {
mInitHelper.ensureInit();
super.handle(request, callback);
}
如何保证路由组件的注册正是它的技术难点,也是不同于Arouter的地方。
然后在handleInternal
方法中找到跟SchemHost匹配的PathHandler
,然后将请求交给对应的PathHandler。
//com.sankuai.waimai.router.common.UriAnnotationHandler
@Override
protected void handleInternal(@NonNull UriRequest request, @NonNull UriCallback callback) {
PathHandler pathHandler = getChild(request);
if (pathHandler != null) {
pathHandler.handle(request, callback);
} else {
// 没找到的继续分发
callback.onNext();
}
}
其中,PathHandler
是根据SchemeHost匹配的处理器:
//com.sankuai.waimai.router.common.UriAnnotationHandler
/**
* 通过scheme+host找对应的PathHandler,找到了才会处理
*/
private PathHandler getChild(@NonNull UriRequest request) {
return mMap.get(request.schemeHost());
}
路由注册方法是register
,它并不需要我们手动来调用:
//com.sankuai.waimai.router.common.UriAnnotationHandler
public void register(String scheme, String host, String path,Object handler, boolean exported, UriInterceptor... interceptors) {
// 没配的scheme和host使用默认值
if (TextUtils.isEmpty(scheme)) {
scheme = mDefaultScheme;
}
if (TextUtils.isEmpty(host)) {
host = mDefaultHost;
}
String schemeHost = RouterUtils.schemeHost(scheme, host);
PathHandler pathHandler = mMap.get(schemeHost);
if (pathHandler == null) {
pathHandler = createPathHandler();
mMap.put(schemeHost, pathHandler);
}
pathHandler.register(path, handler, exported, interceptors);
}
由于它是支持同一个SchemHost可以有多个path,所以它将同一个SchemeHost下的请求全部交给对应的PathHandler。第一次先创建新的PathHandler,然后放到Map中缓存起来,下次从缓存中取出PathHandler。
实际的路由注册是PathHandler
的resgiter
方法。
接下来就是PathHandler的源码:
//com.sankuai.waimai.router.common.PathHandler
public void register(String path, Object target, boolean exported,
UriInterceptor... interceptors) {
if (!TextUtils.isEmpty(path)) {
path = RouterUtils.appendSlash(path);
UriHandler parse = UriTargetTools.parse(target, exported, interceptors);
UriHandler prev = mMap.put(path, parse);
if (prev != null) {
Debugger.fatal("[%s] 重复注册path='%s'的UriHandler: %s, %s", this, path, prev, parse);
}
}
}
//省略无关代码
UriTargetTools
的parse
方法中生成了path对应的真正处理跳转的UriHandler,比如处理Activity跳转的UriHandler是ActivityClassNameHandler
:
package com.sankuai.waimai.router.components;
import android.app.Activity;
import com.sankuai.waimai.router.activity.ActivityClassNameHandler;
import com.sankuai.waimai.router.activity.ActivityHandler;
import com.sankuai.waimai.router.common.NotExportedInterceptor;
import com.sankuai.waimai.router.core.UriHandler;
import com.sankuai.waimai.router.core.UriInterceptor;
import java.lang.reflect.Modifier;
/**
* 跳转目标,支持ActivityClass, ActivityClassName, UriHandler。
*
* Created by jzj on 2018/3/26.
*/
public class UriTargetTools {
public static UriHandler parse(Object target, boolean exported,
UriInterceptor... interceptors) {
UriHandler handler = toHandler(target);
if (handler != null) {
if (!exported) {
handler.addInterceptor(NotExportedInterceptor.INSTANCE);
}
handler.addInterceptors(interceptors);
}
return handler;
}
private static UriHandler toHandler(Object target) {
if (target instanceof UriHandler) {
return (UriHandler) target;
} else if (target instanceof String) {
return new ActivityClassNameHandler((String) target);
} else if (target instanceof Class && isValidActivityClass((Class) target)) {
//noinspection unchecked
return new ActivityHandler((Class<? extends Activity>) target);
} else {
return null;
}
}
private static boolean isValidActivityClass(Class clazz) {
return clazz != null && Activity.class.isAssignableFrom(clazz)
&& !Modifier.isAbstract(clazz.getModifiers());
}
}
关于实际处理跳转的代码请参阅源码,它并不是重点。以上介绍了Router源码的大致流程,其中最重要的还没有讲,就是它是如何自动注册路由的。
UriAnnotationHandler如何注册路由
我们看一下UriAnnotationHandler
的register
方法在哪里调用的。
//com.sankuai.waimai.router.common.UriAnnotationHandler
public void register(String scheme, String host, String path,Object handler, boolean exported, UriInterceptor... interceptors) {
...
}
通过IDE的调用跟踪功能,找到了两处调用:
package com.sankuai.waimai.router.generated;
import com.sankuai.waimai.router.common.IUriAnnotationInit;
import com.sankuai.waimai.router.common.UriAnnotationHandler;
public class UriAnnotationInit_193ec81a29c7c951924b68ab1dc340aa implements IUriAnnotationInit {
public void init(UriAnnotationHandler handler) {
handler.register("aaa", "bbb", "/page1", "com.devnn.library1.ActivityTest1", false);
handler.register("aaa", "bbb", "/page3", "com.devnn.library1.ActivityTest3", false);
}
}
它的位置是对应library1工程的build目录下:
可见,这是APT帮我们生成的代码。
在library1工程中笔者之前声明过两个路由组件:
package com.devnn.library1
import androidx.appcompat.app.AppCompatActivity
import com.sankuai.waimai.router.annotation.RouterUri
@RouterUri(scheme = "aaa", host = "bbb", path = ["/page1"])
class ActivityTest1 : AppCompatActivity() {
...
}
package com.devnn.library1
import androidx.appcompat.app.AppCompatActivity
import com.sankuai.waimai.router.annotation.RouterUri
@RouterUri(scheme = "aaa", host = "bbb", path = ["/page3"])
class ActivityTest3 : AppCompatActivity() {
...
}
UriAnnotationInit_193ec81a29c7c951924b68ab1dc340aa
正是Router帮我们生成的初始化类。它的init方法帮我们完成了这两个Activity的路由注册。
那么它的init初始化方法是在哪里调用的呢?
通过跟踪是在DefaultAnnotationLoader
中调用的:
package com.sankuai.waimai.router.components;
import com.sankuai.waimai.router.Router;
import com.sankuai.waimai.router.core.UriHandler;
import java.util.List;
/**
* 使用ServiceLoader加载注解配置
*
* Created by jzj on 2018/4/28.
*/
public class DefaultAnnotationLoader implements AnnotationLoader {
public static final AnnotationLoader INSTANCE = new DefaultAnnotationLoader();
@Override
public <T extends UriHandler> void load(T handler,
Class<? extends AnnotationInit<T>> initClass) {
List<? extends AnnotationInit<T>> services = Router.getAllServices(initClass);
for (AnnotationInit<T> service : services) {
service.init(handler);
}
}
}
DefaultAnnotationLoader的loader方法是在UriAnnotationHandler
的handle方法中调用的:
//com.sankuai.waimai.router.common.UriAnnotationHandler
@Override
public void handle(@NonNull UriRequest request, @NonNull UriCallback callback) {
mInitHelper.ensureInit();
super.handle(request, callback);
}
handle
方法的第一行代码mInitHelper.ensureInit()
调用了doInit
方法:
//com.sankuai.waimai.router.common.UriAnnotationHandler
private final LazyInitHelper mInitHelper = new LazyInitHelper("UriAnnotationHandler") {
@Override
protected void doInit() {
initAnnotationConfig();
}
};
/**
* @param defaultScheme {@link RouterUri} 没有指定scheme时,则使用这里设置的defaultScheme
* @param defaultHost {@link RouterUri} 没有指定host时,则使用这里设置的defaultHost
*/
public UriAnnotationHandler(@Nullable String defaultScheme, @Nullable String defaultHost) {
mDefaultScheme = RouterUtils.toNonNullString(defaultScheme);
mDefaultHost = RouterUtils.toNonNullString(defaultHost);
}
/**
* @see LazyInitHelper#lazyInit()
*/
public void lazyInit() {
mInitHelper.lazyInit();
}
protected void initAnnotationConfig() {
RouterComponents.loadAnnotation(this, IUriAnnotationInit.class);
}
接着看 RouterComponents.loadAnnotation
方法:
//com.sankuai.waimai.router.components.RouterComponents
@NonNull
private static AnnotationLoader sAnnotationLoader = DefaultAnnotationLoader.INSTANCE;
public static <T extends UriHandler> void loadAnnotation(T handler, Class<? extends AnnotationInit<T>> initClass) {
sAnnotationLoader.load(handler, initClass);
}
可以看到调用的正是DefaultAnnotationLoader
的load
方法。
DefaultAnnotationLoader
的load
方法(参见上文)调用了Router.getAllServcie(initClass)
方法。
那么Router.getAllServices(initClass)
是如何找到AnnotationInit
的实现类呢?
这又回到了门面类Router
:
//com.sankuai.waimai.router.Router
public static <I, T extends I> List<T> getAllServices(Class<I> clazz) {
return ServiceLoader.load(clazz).getAll();
}
可见它是使用ServiceLoader
来加载服务的。
经过以上分析,路由组件是在ServiceLoader
中注册的。
然而,这并不是jdk中的java.util.ServiceLoader
,而是一个自定义的ServiceLoader,不要被它的名字迷惑了。
WMRouter中的ServiceLoader
package com.sankuai.waimai.router.service;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.sankuai.waimai.router.annotation.RouterProvider;
import com.sankuai.waimai.router.components.RouterComponents;
import com.sankuai.waimai.router.core.Debugger;
import com.sankuai.waimai.router.interfaces.Const;
import com.sankuai.waimai.router.utils.LazyInitHelper;
import com.sankuai.waimai.router.utils.SingletonPool;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 通过接口Class获取实现类
* <p>
* Created by jzj on 2018/3/29.
*
* @param <I> 接口类型
*/
public class ServiceLoader<I> {
private static final Map<Class, ServiceLoader> SERVICES = new HashMap<>();
private static final LazyInitHelper sInitHelper = new LazyInitHelper("ServiceLoader") {
@Override
protected void doInit() {
try {
// 反射调用Init类,避免引用的类过多,导致main dex capacity exceeded问题
Class.forName(Const.SERVICE_LOADER_INIT)
.getMethod(Const.INIT_METHOD)
.invoke(null);
Debugger.i("[ServiceLoader] init class invoked");
} catch (Exception e) {
Debugger.fatal(e);
}
}
};
/**
* @see LazyInitHelper#lazyInit()
*/
public static void lazyInit() {
sInitHelper.lazyInit();
}
/**
* 提供给InitClass使用的初始化接口
*
* @param interfaceClass 接口类
* @param implementClass 实现类
*/
public static void put(Class interfaceClass, String key, Class implementClass, boolean singleton) {
ServiceLoader loader = SERVICES.get(interfaceClass);
if (loader == null) {
loader = new ServiceLoader(interfaceClass);
SERVICES.put(interfaceClass, loader);
}
loader.putImpl(key, implementClass, singleton);
}
/**
* 根据接口获取 {@link ServiceLoader}
*/
@SuppressWarnings("unchecked")
public static <T> ServiceLoader<T> load(Class<T> interfaceClass) {
sInitHelper.ensureInit();
if (interfaceClass == null) {
Debugger.fatal(new NullPointerException("ServiceLoader.load的class参数不应为空"));
return EmptyServiceLoader.INSTANCE;
}
ServiceLoader service = SERVICES.get(interfaceClass);
if (service == null) {
synchronized (SERVICES) {
service = SERVICES.get(interfaceClass);
if (service == null) {
service = new ServiceLoader(interfaceClass);
SERVICES.put(interfaceClass, service);
}
}
}
return service;
}
/**
* key --> class name
*/
private HashMap<String, ServiceImpl> mMap = new HashMap<>();
private final String mInterfaceName;
private ServiceLoader(Class interfaceClass) {
if (interfaceClass == null) {
mInterfaceName = "";
} else {
mInterfaceName = interfaceClass.getName();
}
}
private void putImpl(String key, Class implementClass, boolean singleton) {
if (key != null && implementClass != null) {
mMap.put(key, new ServiceImpl(key, implementClass, singleton));
}
}
/**
* 创建指定key的实现类实例,使用 {@link RouterProvider} 方法或无参数构造。对于声明了singleton的实现类,不会重复创建实例。
*
* @return 可能返回null
*/
public <T extends I> T get(String key) {
return createInstance(mMap.get(key), null);
}
/**
* 创建指定key的实现类实例,使用Context参数构造。对于声明了singleton的实现类,不会重复创建实例。
*
* @return 可能返回null
*/
public <T extends I> T get(String key, Context context) {
return createInstance(mMap.get(key), new ContextFactory(context));
}
/**
* 创建指定key的实现类实例,使用指定的Factory构造。对于声明了singleton的实现类,不会重复创建实例。
*
* @return 可能返回null
*/
public <T extends I> T get(String key, IFactory factory) {
return createInstance(mMap.get(key), factory);
}
/**
* 创建所有实现类的实例,使用 {@link RouterProvider} 方法或无参数构造。对于声明了singleton的实现类,不会重复创建实例。
*
* @return 可能返回EmptyList,List中的元素不为空
*/
@NonNull
public <T extends I> List<T> getAll() {
return getAll((IFactory) null);
}
/**
* 创建所有实现类的实例,使用Context参数构造。对于声明了singleton的实现类,不会重复创建实例。
*
* @return 可能返回EmptyList,List中的元素不为空
*/
@NonNull
public <T extends I> List<T> getAll(Context context) {
return getAll(new ContextFactory(context));
}
/**
* 创建所有实现类的实例,使用指定Factory构造。对于声明了singleton的实现类,不会重复创建实例。
*
* @return 可能返回EmptyList,List中的元素不为空
*/
@NonNull
public <T extends I> List<T> getAll(IFactory factory) {
Collection<ServiceImpl> services = mMap.values();
if (services.isEmpty()) {
return Collections.emptyList();
}
List<T> list = new ArrayList<>(services.size());
for (ServiceImpl impl : services) {
T instance = createInstance(impl, factory);
if (instance != null) {
list.add(instance);
}
}
return list;
}
/**
* 获取指定key的实现类。注意,对于声明了singleton的实现类,获取Class后还是可以创建新的实例。
*
* @return 可能返回null
*/
@SuppressWarnings("unchecked")
public <T extends I> Class<T> getClass(String key) {
return (Class<T>) mMap.get(key).getImplementationClazz();
}
/**
* 获取所有实现类的Class。注意,对于声明了singleton的实现类,获取Class后还是可以创建新的实例。
*
* @return 可能返回EmptyList,List中的元素不为空
*/
@SuppressWarnings("unchecked")
@NonNull
public <T extends I> List<Class<T>> getAllClasses() {
List<Class<T>> list = new ArrayList<>(mMap.size());
for (ServiceImpl impl : mMap.values()) {
Class<T> clazz = (Class<T>) impl.getImplementationClazz();
if (clazz != null) {
list.add(clazz);
}
}
return list;
}
@SuppressWarnings("unchecked")
@Nullable
private <T extends I> T createInstance(@Nullable ServiceImpl impl, @Nullable IFactory factory) {
if (impl == null) {
return null;
}
Class<T> clazz = (Class<T>) impl.getImplementationClazz();
if (impl.isSingleton()) {
try {
return SingletonPool.get(clazz, factory);
} catch (Exception e) {
Debugger.fatal(e);
}
} else {
try {
if (factory == null) {
factory = RouterComponents.getDefaultFactory();
}
T t = factory.create(clazz);
Debugger.i("[ServiceLoader] create instance: %s, result = %s", clazz, t);
return t;
} catch (Exception e) {
Debugger.fatal(e);
}
}
return null;
}
@Override
public String toString() {
return "ServiceLoader (" + mInterfaceName + ")";
}
public static class EmptyServiceLoader extends ServiceLoader {
public static final ServiceLoader INSTANCE = new EmptyServiceLoader();
public EmptyServiceLoader() {
super(null);
}
@NonNull
@Override
public List<Class> getAllClasses() {
return Collections.emptyList();
}
@NonNull
@Override
public List getAll() {
return Collections.emptyList();
}
@NonNull
@Override
public List getAll(IFactory factory) {
return Collections.emptyList();
}
@Override
public String toString() {
return "EmptyServiceLoader";
}
}
}
ServiceLoader
的load
方法第一行代码就是初始化ServiceLoader:
//com.sankuai.waimai.router.service.ServiceLoader
public static <T> ServiceLoader<T> load(Class<T> interfaceClass) {
sInitHelper.ensureInit();
...
}
//com.sankuai.waimai.router.service.ServiceLoader
private static final LazyInitHelper sInitHelper = new LazyInitHelper("ServiceLoader") {
@Override
protected void doInit() {
try {
// 反射调用Init类,避免引用的类过多,导致main dex capacity exceeded问题
Class.forName(Const.SERVICE_LOADER_INIT)
.getMethod(Const.INIT_METHOD)
.invoke(null);
Debugger.i("[ServiceLoader] init class invoked");
} catch (Exception e) {
Debugger.fatal(e);
}
}
};
这正是这个自定义ServiceLoader玄机所在,它通过反射调用
com.sankuai.waimai.router.generated.ServiceLoaderInit
这个固定的类,调用它的init方法来初始化ServiceLoader。WMRouter源码中并没有ServiceLoaderInit
这个类,build目录也没有,因此大胆猜测它是由gradle插件帮我们生成的。
我们将生成的apk反编译,找到了ServiceLoaderInit
这个类,它的字节码内容如下:
.method public static init()V
.registers 0
invoke-static {}, Lcom/sankuai/waimai/router/generated/service/ServiceInit_7ba49f44b4136fbacadf8b749184ccb8;->init()V
invoke-static {}, Lcom/sankuai/waimai/router/generated/service/ServiceInit_569998d498513846731787b941d88272;->init()V
invoke-static {}, Lcom/sankuai/waimai/router/generated/service/ServiceInit_915e2ffdfef22c5fbf4a1c47a37e69a5;->init()V
return-void
.end method
可见,它就是将APT生成的各种ServiceInit_xxx类的init方法调用了一遍。
到这里,我们已经知道了路由组件是如何自动注册的。
看流程有点复杂也有点绕,其实最有技术含量的代码就是ServiceLoader
。
WMRouter的ServiceLoader
功能类似于jdk中java.util.ServiceLoader
,用来加载服务的,然后又不同于java.util.ServiceLoader
。
不同点在于WMRouter的ServiceLoader
可以自定义服务的构造方法,而且可以加载特定的服务(带有key的服务),而不是所有服务。
另一个不同点是WMRouter的ServiceLoader
加载服务方式并没有采用SPI技术,而且采用反射机制加载ServiceLoaderInit
类。ServiceLoaderInit
采用字节码插桩技术动态生成,它是用来初始化APT生成的ServiceInit_xxx
类,初始化函数实际上就是往ServiceLoader
中添加服务,这样就完成了服务的注册。在ServiceInit_xxx
类中提供了注册接口,ServiceLoaderInit
类中完成注册接口的调用。ServiceLoaderInit
是在ServiceLoader
的load方法首次调用时通过反射加载。
笔者原创,转载请注明出处:https://blog.csdn.net/devnn/article/details/136969237
@RouterUri注解的作用
在library1工程中使用@RouterUri
给两个Activity分别是ActivityTest1
和ActivityTest3
添加注解,在library1的build/generated/source/kapt/debug
目录下会生成IUriAnnotationInit
服务的实现类:
package com.sankuai.waimai.router.generated;
import com.sankuai.waimai.router.common.IUriAnnotationInit;
import com.sankuai.waimai.router.common.UriAnnotationHandler;
public class UriAnnotationInit_193ec81a29c7c951924b68ab1dc340aa implements IUriAnnotationInit {
public void init(UriAnnotationHandler handler) {
handler.register("aaa", "bbb", "/page1", "com.devnn.library1.ActivityTest1", false);
handler.register("aaa", "bbb", "/page3", "com.devnn.library1.ActivityTest3", false);
}
}
同时在该目录下会生成IUriAnnotationInit
服务的注册类:
package com.sankuai.waimai.router.generated.service;
import com.sankuai.waimai.router.common.IUriAnnotationInit;
import com.sankuai.waimai.router.service.ServiceLoader;
public class ServiceInit_7ba49f44b4136fbacadf8b749184ccb8 {
public static void init() {
ServiceLoader.put(IUriAnnotationInit.class, "com.sankuai.waimai.router.generated.UriAnnotationInit_193ec81a29c7c951924b68ab1dc340aa", com.sankuai.waimai.router.generated.UriAnnotationInit_193ec81a29c7c951924b68ab1dc340aa.class, false);
}
}
@RouterService注解的作用
当使用@RouterService注解会生成Service的注册类。
示例:在library1工程中声明一个@RouterService
组件。
package com.devnn.library1
import android.util.Log
import com.devnn.baselibrary.IWMService
import com.sankuai.waimai.router.annotation.RouterService
@RouterService(interfaces=[IWMService::class], key =["WMLib1Service"])
class WMLib1Service:IWMService{
override fun init() {
Log.d("IWMService", "WMLib1Service_init")
}
}
在libary1工程的build/generated/source/kapt/debug
目录下生成的类:
package com.sankuai.waimai.router.generated.service;
import com.devnn.baselibrary.IWMService;
import com.devnn.library1.WMLib1Service;
import com.sankuai.waimai.router.service.ServiceLoader;
public class ServiceInit_569998d498513846731787b941d88272 {
public static void init() {
ServiceLoader.put(IWMService.class, "WMLib1Service", WMLib1Service.class, false);
}
}
示例:在library2工程中声明一个@RouterService组件。
package com.devnn.library2
import android.util.Log
import com.devnn.baselibrary.IWMService
import com.sankuai.waimai.router.annotation.RouterService
@RouterService(interfaces=[IWMService::class], key =["WMLib2Service"])
class WMLib2Service:IWMService {
override fun init() {
Log.d("IWMService", "WMLib2Service_init")
}
}
在libary2工程的build/generated/source/kapt/debug
目录下生成的类:
package com.sankuai.waimai.router.generated.service;
import com.devnn.baselibrary.IWMService;
import com.devnn.library2.WMLib2Service;
import com.sankuai.waimai.router.service.ServiceLoader;
public class ServiceInit_915e2ffdfef22c5fbf4a1c47a37e69a5 {
public static void init() {
ServiceLoader.put(IWMService.class, "WMLib2Service", WMLib2Service.class, false);
}
}
Gradle插件自动生成的ServiceLoaderInit
类的字节码上文已经贴出,笔者将它转成了Java代码:
package com.sankuai.waimai.router.generated.ServiceLoaderInit;
public class ServiceLoaderInit {
public ServiceLoaderInit() {
com.sankuai.waimai.router.generated.service.ServiceInit_7ba49f44b4136fbacadf8b749184ccb8.init();
com.sankuai.waimai.router.generated.service.ServiceInit_569998d498513846731787b941d88272.init();
com.sankuai.waimai.router.generated.service.ServiceInit_915e2ffdfef22c5fbf4a1c47a37e69a5.init();
}
}
关于如何生成ServiceLaoderInit
的代码,有兴趣可以参阅源码:
https://github.com/meituan/WMRouter/blob/master/WmPlugin/plugin/src/main/java/com/sankuai/waimai/router/plugin/WMRouterTransform.java
总结
经过上文分析,WMRouter的Uri跳转是由UriAnnotationHandler
处理器完成的。在UriAnnotationHandler的handle
方法中首先初始化由@RouterUri
注解生成的服务。初始化功能即完成路由组件的注册。这个过程分两步,第一步是先找到服务,这个是由ServiceLoader完成的。第二步是注册,这个是服务的init(...)
方法完成的。整体流程如下:
笔者原创,转载请注明出处:https://blog.csdn.net/devnn/article/details/136969237