WMRouter源码解析
JAVA SPI
SPI全称Service Provider Interface,是Java提供的一套用来被第三方实现或者扩展的API,它可以用来启用框架扩展和替换组件。
SPI
SPI(Service Provider Interface),是java提供的一套用来被第三方实现或者扩展的API。它可以用来启用框架扩展和替换组件。Java SPI 实际上是“基于接口的编程+策略模式+配置文件”组合实现的动态加载机制。
使用步骤:
1、当服务提供者提供了接口的一种具体实现后,在jar包的META-INF/services目录下创建一个以“接口全限定名”为命名的文件,内容为实现类的全限定名;
2、接口实现类所在的jar包放在主程序的classpath中;
3、主程序通过java.util.ServiceLoder动态装载实现模块,它通过扫描META-INF/services目录下的配置文件找到实现类的全限定名,把类加载到JVM;
4、SPI的实现类必须携带一个不带参数的构造方法;
ServiceLoader
- java提供的ServiceLoader。原理是根据传入的接口类,遍历
META-INF/services
目录下的以该类命名的文件中的所有类,并实例化返回。通过返回一个Iterator对象能够做到对服务实例的懒加载。 - 用简洁的来概括,SPI编程方式本质是获取META-INF/services下的类的完整名称(字符串),然后根据类的完整名称通过类的加载器来实现动态加载的
WMRouter SPI 实现原理
WMRouter的实现原理也是基于SPI的编程方式,通过路由路径(本质也是字符串)来获取类的实现,实现不强制依赖于具体的实现类来调用具体的实现类。
基于SPI (Service Provider Interfaces) 的设计思想,WMRouter提供了ServiceLoader模块,类似Java中的java.util.ServiceLoader
,但功能更加完善。通过ServiceLoader可以在一个App的多个模块之间通过接口调用代码,实现模块解耦,便于实现组件化、模块间通信,以及和依赖注入类似的功能等。其特点如下:
- 使用注解自动配置
- 支持获取接口的所有实现,或根据Key获取特定实现
- 支持获取Class或获取实例
- 支持无参构造、Context构造,或自定义Factory、Provider构造
- 支持单例管理
- 支持方法调用
基本实现
数据结构
根据SPI的机制,一个接口可以有多个实现类,因此可以设计一个最为简单的数据存储结构
class ServiceImpl{
/**
需要实现的接口
**/
private String implementation;
/**
实现了接口的类
**/
private Class[] implementationClazz;
}
由于路由框架,本质是希望通过路由的路径查找到唯一指定的实现,因此上面的数据结构不满足需求。因此需要增加路径的路径属性,保证获取的实现类是唯一的。因此数据结构设计如下:
// 具体参见源码 interfaces module 中 com.sankuai.waimai.router.service.ServiceImpl
class ServiceImpl{
/**
* 路由的唯一路径
*/
private final String key;
/**
* 需要实现接口或者被继承的父类,调用方可以调用接口或者父类中的方法。
*/
private final String implementation;
/**
* 实现类
*/
private final Class implementationClazz;
}
项目中必定存在多个路径,因此可以将路由的路径和ServiceImpl通过map的形式存在在内存中。因此serviceLoadr中存在一个重要的数据类型。
// 具体参见源码 router module 中 com.sankuai.waimai.router.service.ServiceLoader
// 将路由路径和实现类一一对应的保存起来
private HashMap<String, ServiceImpl> mMap = new HashMap<>();
// 保存数据的方法
private void putImpl(String key, Class implementClass, boolean singleton) {
if (key != null && implementClass != null) {
mMap.put(key, new ServiceImpl(key, implementClass, singleton));
}
}
// 读取数据 提供多个方式get,可以指定provider,等等
public <T extends I> T get(String key) {
// 根据 路径获取实现
return createInstance(mMap.get(key), null);
}
框架的作者可能考虑,由于路由的路径在整个项目中是唯一的,因此map的存储会比较多。因此框架作者又进行了一个数据结构的封装
// 具体参见源码 router module 中 com.sankuai.waimai.router.service.ServiceLoader
// 将需要实现的接口/被继承的父类作为key ServiceLoader作为value存储
private static final Map<Class, ServiceLoader> SERVICES = new HashMap<>();
// 存储
/**
* @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);
}
// 读取
public static <T> ServiceLoader<T> load(Class<T> interfaceClass) {
// 通过 ServiceLoaderInit 初始化接口
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;
}
存储数据
根据以上数据结构的分析,可以获知,我们可以通过路由路径和接口类来获取唯一的实现类。我们可以调用ServiceLoader#put方法将数据进行存储,通过load方法获取实现类。由于进行数据存储的代码相似因此可以采用编译注解的方式,在编译过程中自动生成方法。
-
编译注解
// 参见源码 interfaces module @Target(ElementType.TYPE) // 用于注解接口或者类 @Retention(RetentionPolicy.CLASS) // 编译注解 public @interface RouterService { /** * 实现的接口(或继承的父类) */ Class[] interfaces(); /** * 同一个接口的多个实现类之间,可以通过唯一的key区分。 */ String[] key() default {}; /** * 是否为单例。如果是单例,则使用ServiceLoader.getService不会重复创建实例。 */ boolean singleton() default false; }
-
自动生成代码
@AutoService(Processor.class) // 注解处理器,能够处理源码中的注解 @SupportedSourceVersion(SourceVersion.RELEASE_7) public class ServiceAnnotationProcessor extends BaseProcessor{ @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) { // 判断是否解析完成 if (env.processingOver()) { //生成文件 generateInitClass(); } else { //处理注解过程 processAnnotations(env); } return true; } /** 处理注解过程: 1.获取所有被RouterService注解的类。 2.获取RouterService的注解属性interfaces,key,singleton 3.将注解保存为数据结构 Map<String, ServiceImpl> mMap; **/ private void processAnnotations(RoundEnvironment env) { } // 生成类文件 private void generateInitClass(){ // 遍历存储的数据 for (Map.Entry<String, Entity> entry : mEntityMap.entrySet()) { for (ServiceImpl service : entry.getValue().getMap().values()) { // 构造表达式 ServiceLoader.put("注解中的interface类", "key字符串", "被注解的类", "单例标识"); generator.put(entry.getKey(), service.getKey(), service.getImplementation(), service.isSingleton()); } } /** 1. 生成构造函数 2. 生成静态方法 void init() **/ generator.build(); } }
因此编译生成文件为
public class ServiceInit_md5 { public ServiceInit_md5() { } public static void init() { ServiceLoader.put("注解中的interface类", "key字符串", "被注解的类", "单例标识"); } }
获取数据
获取数据,本质上是通过key和实现的接口类来获取实现。
- 简单的调用
/** * 创建指定key的实现类实例,使用 {@link RouterProvider} 方法或无参数构造。对于声明了singleton的实现类,不会重复创建实例。 * * @return 找不到或获取、构造失败,则返回null */ public static <I, T extends I> T getService(Class<I> clazz, String key) { return ServiceLoader.load(clazz).get(key); }
-
通过这个来实现调用实现的方法
/** * 调用方法。方法应该实现 {@link Func0} ~ {@link FuncN} 接口,根据参数个数匹配接口。 */ @SuppressWarnings("unchecked") public static <T> T callMethod(String key, Object... args) { switch (args.length) { case 0: return (T) getService(Func0.class, key).call(); case 1: return (T) getService(Func1.class, key).call(args[0]); case 2: return (T) getService(Func2.class, key).call(args[0], args[1]); ... } }
WMRouter 源码结构
- compiler:处理interfaces定义的注解,生成相应的源文件。
- interfaces: 定义了五种注解,分别是RouterPager、RouterRegex、RouterUri、RouterProvider、RouterService。
- plugin:自定义一个名为WMRouter 的gradle插件,将注解生成器生成的初始化类汇总到ServiceLoaderInit,运行时直接调用ServiceLoaderInit
- router:核心库
WMRouter 的URI 分发
URI(Uniform Resource Identifier,统一资源标识符)是一个用于标识某一互联网资源名称的字符串。Android中URI常用的几个部分主要是scheme、host、path和query
WMRouter的另一个重要功能是URI分发,URI分发功能可用于多工程之间的页面跳转、动态下发URI链接的跳转等场景,特点如下:
- 支持多scheme、host、path
- 支持URI正则匹配
- 页面配置支持Java代码动态注册,或注解配置自动注册
- 支持配置全局和局部拦截器,可在跳转前执行同步/异步操作,例如定位、登录等
- 支持单次跳转特殊操作:Intent设置Extra/Flags、设置跳转动画、自定义StartActivity操作等
- 支持页面Exported控制,特定页面不允许外部跳转
- 支持配置全局和局部降级策略
- 支持配置单次和全局跳转监听
- 完全组件化设计,核心组件均可扩展、按需组合,实现灵活强大的功能
本质上通过URI获取到处理URI的类(WMRouter中称为Handler),Handler对URI和实现类的不同进行个性化处理。
根据对URI的分析可以设计出最为简单的数据结构
class UriHandlerImpl{
String scheme;
String host;
String path;
// 处理的类
class Handles;
}
由于Handler处理机制复杂,WMRouter设计了多种数据结构。将path和Handler通过map一一对应起来。因此后面从类的注解到Hanlder处理的方式来剖析源码。
注解
关于Handler的注解参见源码interface module 中的RouterUri,RouterRegex,RouterPage。
RouterUri
这个注解的功能是指定一个URI跳转,可以注解在Activity和继承UriHandler类上面。
@Target(ElementType.TYPE) // 注解在接口或者类
@Retention(RetentionPolicy.CLASS) // 编译时注解
public @interface RouterUri {
String[] path();
String scheme() default "";
String host() default "";
boolean exported() default false;
Class[] interceptors() default {};
}
RouterRegex
这个注解功能和RouterUri注解类似,不同的是URI路径使用正则表达式,并且可以设置匹配到数据的优先级。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface RouterRegex {
String regex();// 正则表达式
int priority() default 0; //优先级
boolean exported() default false;
Class[] interceptors() default {};
}
RouterPage
这个注解的功能是指定一个URI跳转,可以注解在Activity和继承UriHandler类,继承fragment上面。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface RouterPage {
String[] path();
Class[] interceptors() default {};
}
编译生成源码
WMRouter的 Compiler通过 APT技术在编译过程中解析编译注解,然后通过javapoet生成.java文件。
UriAnnotationProcessor
UriAnnotationProcessor的功能是解析编译注解RouterUri,并且生成文件。伪代码如下:
@AutoService(Processor.class)
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class UriAnnotationProcessor extends BaseProcessor {
// 处理编译注解
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
...
// 遍历RouterUri注解
for (Element element : env.getElementsAnnotatedWith(RouterUri.class)) {
...
// 创建Handler。格式:"com.demo.TestActivity" 或 new TestHandler()
CodeBlock handler = buildHandler(isActivity, cls);
// 创建Interceptors。格式: new Interceptor1(), new Interceptor2()
CodeBlock interceptors = buildInterceptors(getInterceptors(uri));
String[] pathList = uri.path();
for (String path : pathList) {
/**创建代码块 格式 handler.register("scheme","host","path",handler,
exported,Interceptors);
hanlder,Interceptors 参见注释;exported 为bool类型
**/
builder.addStatement("handler.register($S, $S, $S, $L, $L$L)",
uri.scheme(),
uri.host(),
path,
handler,
uri.exported(),
interceptors);
}
}
/**
创建两个文件
1.生成UriAnnotationInit_md5.java。功能是将配置的路径和handler对应起来起来。
2.生成生成ServiceInit_md5.java文件.功能是将上面生成的UriAnnotationInit_md5.java和IUriAnnotationInit.class对应起来。保证可以通过ServerLoader获取UriAnnotationInit_md5。
**/
buildHandlerInitClass(builder.build(), "UriAnnotationInit" + Const.SPLITTER + hash,
Const.URI_ANNOTATION_HANDLER_CLASS, Const.URI_ANNOTATION_INIT_CLASS);
}
}
生成的代码类似
public class UriAnnotationInit_md5_1 implements IUriAnnotationInit {
public UriAnnotationInit_md5_1() {
}
public void init(UriAnnotationHandler handler){
handler.register("scheme","host","path",handler,
exported,Interceptors);
...
}
}
public class ServiceInit_md5 {
public ServiceInit_md5() {
}
public static void init() {
ServiceLoader.put(IUriAnnotationInit.class, "UriAnnotationInit_md5_1的完整类名", UriAnnotationInit_md5_1.class, "单例标识");
}
}
通过以上源码分析可以获取到的数据存储结构是:
- 处理RouterUri的handler存储在private final Map<String, PathHandler> mMap;key值是uri,value值是PathHandler。
- UriAnnotationInit_md5_1,UriAnnotationInit_md5_1的类名存储在HashMap<String, ServiceImpl> mMap 中。
可以猜想WMRouter的Handler的过程类似先通过ServiceLoader,获取到UriAnnotationHandler。UriAnnotationHandler通过注解配置的Uri找到最终处理的Handler。
PageAnnotationProcessor
PageAnnotationProcessor的处理过程和UriAnnotationProcessor的处理过程相似。
@AutoService(Processor.class)
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class PageAnnotationProcessor extends BaseProcessor {
//处理编译注解
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
...
// 获取RouterPage的注解
for (Element element : env.getElementsAnnotatedWith(RouterPage.class)){
...
CodeBlock handler;
if(isFragment || isFragmentV4){
// 创建Handler。格式: new FragmentTransactionHandler("FragmentName")
handler = buildFragmentHandler(cls);
}else {
// 创建Handler。格式:"com.demo.TestActivity" 或 new TestHandler()
handler = buildHandler(isActivity, cls);
}
/**创建代码块 格式 handler.register("scheme","host","path",handler,
exported,Interceptors);
hanlder,Interceptors 参见注释;exported 为bool类型
**/
CodeBlock interceptors = buildInterceptors(getInterceptors(page));
String[] pathList = page.path();
for (String path : pathList) {
/**创建代码块 格式 handler.register("scheme","host","path",handler,
exported,Interceptors);
hanlder,Interceptors 参见注释;exported 为bool类型
**/
builder.addStatement("handler.register($S, $L$L)",
path,
handler,
interceptors);
}
}
/**
创建两个文件
1.生成PageAnnotationInit_md5.java。功能是将配置的路径和handler对应起来起来。
2.生成生成ServiceInit_md5.java文件.功能是将上面生成的PageAnnotationInit_md5.java和PageAnnotationInit.class对应起来。保证可以通过ServerLoader获取PageAnnotationInit_md5。
**/
buildHandlerInitClass(builder.build(), "PageAnnotationInit" + Const.SPLITTER + hash,
Const.PAGE_ANNOTATION_HANDLER_CLASS, Const.PAGE_ANNOTATION_INIT_CLASS);
}
}
生成的源码类似
public class PageAnnotationInit_md5_1 implements IPageAnnotationInit {
public PageAnnotationInit_md5_1() {
}
public void init(PageAnnotationInit handler){
handler.register("path",handler,
exported,Interceptors);
...
}
}
public class ServiceInit_md5 {
public ServiceInit_md5() {
}
public static void init() {
ServiceLoader.put(IPageAnnotationInit.class, "PageAnnotationInit_md5_1的完整类名", PageAnnotationInit_md5_1.class, "单例标识");
}
}
RegexAnnotationProcessor
RegexAnnotationProcessor的处理过程和UriAnnotationProcessor的处理过程相似。
@AutoService(Processor.class)
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class RegexAnnotationProcessor extends BaseProcessor {
...
//遍历 RouterRegex 注解
for (Element element : env.getElementsAnnotatedWith(RouterRegex.class)){
CodeBlock handler = buildHandler(isActivity, cls);
CodeBlock interceptors = buildInterceptors(getInterceptors(regex));
// regex, activityClassName/new Handler(), exported, priority, new Interceptors()
builder.addStatement("handler.register($S, $L, $L, $L$L)",
regex.regex(),
handler,
regex.exported(),
regex.priority(),
interceptors
);
}
buildHandlerInitClass(builder.build(), "RegexAnnotationInit" + Const.SPLITTER + hash,
Const.REGEX_ANNOTATION_HANDLER_CLASS, Const.REGEX_ANNOTATION_INIT_CLASS);
}
生成的源码类似
public class RegexAnnotationInit_md5_1 implements IRegexAnnotationInit {
public RegexAnnotationInit_md5_1() {
}
public void init(RegexAnnotationHandler handler){
handler.register("regex"handler,false,priority,Interceptors);
...
}
}
public class ServiceInit_md5 {
public ServiceInit_md5() {
}
public static void init() {
ServiceLoader.put(IRegexAnnotationInit.class, "UriAnnotationInit_md5_1的完整类名", UriAnnotationInit_md5_1.class, false);
}
}
plugin
对以上部分进行小结:
- interfaces 模块主要是提供了注解和ServiceImpl这个数据结构。
- compiler 主要功能是提供了对注解的解析,并且生成java文件。
plugin的主要功能:
- 提供debug调试的开关.
- 将注解生成器生成的初始化类汇总到ServiceLoaderInit,运行时直接调用ServiceLoaderInit。
plugin为何要将ServiceInit_md5汇总到ServiceLoaderInit这个类中,WMRouter中注释提到
“反射调用Init类,避免引用的类过多,导致main dex capacity exceeded 问题”。这个问题主要是跟MultiDex有关。具体的对Android 提供的 MultiDex的加载机制尚未清楚了解,不知道main dex 和其他dex 文件加载的关系。
原方案:是获取所有ServiceInit_md5文件,并且调用其中init()方法。
生成的文件是:
public class ServiceLoaderInit
{
public static void init()
{
ServiceInit_md5_1.init();
ServiceInit_md5_2.init();
ServiceInit_md5_3.init();
...
}
}
Handler处理过程
Handler的处理过程参见核心库Router module
初始化
-
初始化DefaultRootUriHandler
// 主工程调用,一般在Application中调用。 DefaultRootUriHandler rootHandler = new DefaultRootUriHandler(context); // 设置全局跳转完成监听器,可用于跳转失败时统一弹Toast提示,做埋点统计等。 rootHandler.setGlobalOnCompleteListener(DefaultOnCompleteListener.INSTANCE); // 初始化 保存到 static RootUriHandler ROOT_HANDLER;单例模式 Router.init(rootHandler); // 初始化源码 public DefaultRootUriHandler(Context context) { this(context, null, null); } 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); }
-
继承关系
ChainedHandler extends UriHandler{} RootUriHandler extends ChainedHandler {} DefaultRootUriHandler extends RootUriHandler{}
由此可知,mPageAnnotationHandler,mUriAnnotationHandler,mRegexAnnotationHandler,StartUriHandler 这几个handler存储在PriorityList mHandlers中。
源码参见
public class ChainedHandler extends UriHandler { // xxhandler存储的数据结果 优先级 由PriorityList 来控制 private final PriorityList<UriHandler> mHandlers = new PriorityList<>(); /** * 添加一个Handler * @param priority 优先级。优先级越大越先执行;相同优先级,先加入的先执行。 */ public ChainedHandler addChildHandler(@NonNull UriHandler handler, int priority) { mHandlers.addItem(handler, priority); return this; } // 迭代器方式取出xxhandler进行处理 private void next(@NonNull final Iterator<UriHandler> iterator, @NonNull final UriRequest request, @NonNull final UriCallback callback) { if (iterator.hasNext()) { UriHandler t = iterator.next(); t.handle(request, new UriCallback() { @Override public void onNext() { next(iterator, request, callback); } @Override public void onComplete(int resultCode) { callback.onComplete(resultCode); } }); } else { callback.onNext(); } }
-
初始ServerLoader和其他Handler
// 主工程调用,一般在Application中调用。 // 懒加载后台初始化(可选) new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... voids) { Router.lazyInit(); return null; } }.execute();
Router.java中的初始化
public class Router{ public static void lazyInit() { ServiceLoader.lazyInit(); getRootHandler().lazyInit(); } }
ServiceLoader.java中的初始化
/** * @see LazyInitHelper#lazyInit() */ public static void lazyInit() { sInitHelper.lazyInit(); } // 最终调用到 private static final LazyInitHelper sInitHelper = new LazyInitHelper("ServiceLoader") { @Override protected void doInit() { try { // 反射调用Init类,避免引用的类过多,导致main dex capacity exceeded问题 /** * 使用反射调用 * ServiceLoaderInit 的 init方法 ServiceLoaderInit 是 plugin生成的,源码参见plugin中的文档。 */ Class.forName(Const.SERVICE_LOADER_INIT) .getMethod(Const.INIT_METHOD) .invoke(null); Debugger.i("[ServiceLoader] init class invoked"); } catch (Exception e) { Debugger.fatal(e); } } };
其他Handler初始化
其他hander指的是非PageAnnotationHandler,UriAnnotationHandler,RegexAnnotationHandler,StartUriHandler。
public class Router{ public static void lazyInit() { ServiceLoader.lazyInit(); // 对handler进行初始化 getRootHandler().lazyInit(); } } class DefaultRootUriHandler{ public void lazyInit() { /**初始化三种处理器**/ mPageAnnotationHandler.lazyInit(); mUriAnnotationHandler.lazyInit(); mRegexAnnotationHandler.lazyInit(); } } // 以上三种的lazyInit最终是调用编译注解产生的文件 class PageAnnotationHandler{ ... protected void initAnnotationConfig() { RouterComponents.loadAnnotation(this, IPageAnnotationInit.class); } } class RegexAnnotationHandler{ ... protected void initAnnotationConfig() { RouterComponents.loadAnnotation(this, IRegexAnnotationInit.class); } } public class UriAnnotationHandler{ protected void initAnnotationConfig() { RouterComponents.loadAnnotation(this, IUriAnnotationInit.class); } } // 最终调用到 具体调用到的类可以参见上面的说明 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) { // 注意这里,通过ServiceLoader获取所有实现类 List<? extends AnnotationInit<T>> services = Router.getAllServices(initClass); for (AnnotationInit<T> service : services) { // 调用init方法将path 和 Hanlder对应起来 service.init(handler); } } }
-
Handler处理过程
handler调用接口比较多,但是原理基本是相同的,只是封装提供给外部的参数不同。因此分析其中一个为例子。
Demo 源码
@RouterUri(path = "/test_activity")
public class TestBasicActivity extends BaseActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
根据上面的分析,编译过程中会生成三个源文件
public class UriAnnotationInit_xxx implements IUriAnnotationInit {
public UriAnnotationInit_xxx() {
}
public void init(UriAnnotationHandler handler){
handler.register("", "", "/test_activity", "com.sankuai.waimai.router.demo.basic.TestBasicActivity", false, new UriInterceptor[0]);
}
}
public class ServiceInit_md5 {
public ServiceInit_md5() {
}
public static void init() {
ServiceLoader.put(IUriAnnotationInit.class, "com.sankuai.waimai.router.generated.UriAnnotationInit_xxx", UriAnnotationInit_xxx.class, false);
}
}
public class ServiceLoaderInit
{
public static void init()
{
ServiceInit_md5.init();
}
}
由初始化过程可以知道:
- 通过ServiceLoader.java的初始,将IUriAnnotationInit.class 和UriAnnotationInit_xxx的ServerImpl对应起来
- 通过getRootHandler().lazyInit();调用UriAnnotationHandler#initAnnotationConfig。将path(“test_activity”)与handler对应起来。
public class UriAnnotationHandler extends UriHandler {
// path --- handler进行对应
private final Map<String, PathHandler> mMap = new HashMap<>();
...
//保存handler
public void register(String scheme, String host, String path,
Object handler, boolean exported, UriInterceptor... interceptors) {
...
// 组装uri
String schemeHost = RouterUtils.schemeHost(scheme, host);
PathHandler pathHandler = mMap.get(schemeHost);
if (pathHandler == null) {
//创建 handler
pathHandler = createPathHandler();
mMap.put(schemeHost, pathHandler);
}
// 注册 handler
// 注意 hander 为 字符串"com.sankuai.waimai.router.demo.basic.TestBasicActivity"
// PathHander 内存用
// CaseInsensitiveNonNullMap<UriHandler> mMap = new CaseInsensitiveNonNullMap<>() 进行存储
pathHandler.register(path, handler, exported, interceptors);
}
@Override
protected void handleInternal(@NonNull UriRequest request, @NonNull UriCallback callback) {
// 通过uri 获取 handler
PathHandler pathHandler = getChild(request);
if (pathHandler != null) {
pathHandler.handle(request, callback);
} else {
// 没找到的继续分发
callback.onNext();
}
}
}
// PathHandler 处理源码
public class PathHandler extends UriHandler{
public void register(String path, Object target, boolean exported,
UriInterceptor... interceptors) {
if (!TextUtils.isEmpty(path)) {
path = RouterUtils.appendSlash(path);
//注意这个,通过 target转换为特定的handler
UriHandler parse = UriTargetTools.parse(target, exported, interceptors);
// key --- path
// value -- uirHandler
UriHandler prev = mMap.put(path, parse);
if (prev != null) {
Debugger.fatal("[%s] 重复注册path='%s'的UriHandler: %s, %s", this, path, prev, parse);
}
}
}
}
// UriTargetTools
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) {
// Demo中handler为 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());
}
}
根据Demo 可知,“test_activity”和PathHandler存储在UriAnnotationHandler的map中。PathHandler中也存在一个map将path和最终处理的Handler一一对应起来。根据Demo最终处理的Handler是ActivityClassNameHandler。ActivityClassNameHandler的继承关系是
public abstract class AbsActivityHandler extends UriHandler{
}
public class ActivityClassNameHandler extends AbsActivityHandler {
}
Demo 调用源码
Router.startUri(this, "/test_activity");
Router Handler处理过程
class Router{
...
public static void startUri(Context context, String uri) {
getRootHandler().startUri(new UriRequest(context, uri));
}
}
public class RootUriHandler extends ChainedHandler{
...
public void startUri(@NonNull UriRequest request){
...
// 根据继承关系
handle(request, new RootUriCallback(request));
}
}
public abstract class UriHandler {
// 处理uri
public void handle(@NonNull final UriRequest request, @NonNull final UriCallback callback) {
if (shouldHandle(request)) {
// 处理拦截器
// 处理 uri 调用到ChainedHandler的handleInternal
handleInternal(request, callback);
}
}
}
class ChainedHandler extends UriHandler{
private final PriorityList<UriHandler> mHandlers = new PriorityList<>();
@Override
protected boolean shouldHandle(@NonNull UriRequest request) {
// 初始化过程中已经存储,不为空
return !mHandlers.isEmpty();
}
@Override
protected void handleInternal(@NonNull final UriRequest request, @NonNull final UriCallback callback) {
/**
// 通过遍历mHandlers依次将uri分发给PageAnnotationHandler,
UriAnnotationHandler,RegexAnnotationHandler
由于“/test_activity”是存储在
UriAnnotationHandler#Map<String, PathHandler> mMap中,因此由UriAnnotationHandler进行处理。
**/
next(mHandlers.iterator(), request, callback);
}
}
UriAnnotationHandler处理源码
public class UriAnnotationHandler extends UriHandler {
// path --- handler进行对应
private final Map<String, PathHandler> mMap = new HashMap<>();
...
//保存handler
public void register(String scheme, String host, String path,
Object handler, boolean exported, UriInterceptor... interceptors) {
...
// 组装uri
String schemeHost = RouterUtils.schemeHost(scheme, host);
PathHandler pathHandler = mMap.get(schemeHost);
if (pathHandler == null) {
//创建 handler
pathHandler = createPathHandler();
mMap.put(schemeHost, pathHandler);
}
// 注册 handler
// 注意 hander 为 字符串"com.sankuai.waimai.router.demo.basic.TestBasicActivity"
pathHandler.register(path, handler, exported, interceptors);
}
@Override
protected void handleInternal(@NonNull UriRequest request, @NonNull UriCallback callback) {
// 通过uri 获取 handler
PathHandler pathHandler = getChild(request);
if (pathHandler != null) {
pathHandler.handle(request, callback);
} else {
// 没找到的继续分发
callback.onNext();
}
}
}
// PathHandler 处理源码
public class PathHandler extends UriHandler{
public void register(String path, Object target, boolean exported,
UriInterceptor... interceptors) {
if (!TextUtils.isEmpty(path)) {
path = RouterUtils.appendSlash(path);
//注意这个,通过 target转换为特定的handler
UriHandler parse = UriTargetTools.parse(target, exported, interceptors);
// key --- path
// value -- uirHandler
UriHandler prev = mMap.put(path, parse);
if (prev != null) {
Debugger.fatal("[%s] 重复注册path='%s'的UriHandler: %s, %s", this, path, prev, parse);
}
}
}
}
// UriTargetTools
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) {
// Demo中handler为 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#startUri
- ChainedHandler#handle,继承父类的UriHandler#handle
- ChainedHandler#handleInternal,最终调用到ChainedHandler#next
- 通过遍历处理获调用UriAnnotationHandler#handleInternal,根据uri获取PathHandler
- 调用pathHandler#handle,继承父类uriHandler#handle。
- 根据ActivityClassNameHandler的继承关系,最终调用到ActivityClassNameHandler。
ActivityClassNameHandler继承关系
public abstract class AbsActivityHandler extends UriHandler{
}
public class ActivityClassNameHandler extends AbsActivityHandler {
}
处理Activity的源码
public abstract class AbsActivityHandler extends UriHandler{
protected void handleInternal(@NonNull UriRequest request, @NonNull UriCallback callback) {
// 创建Intent
Intent intent = createIntent(request);
if (intent == null || intent.getComponent() == null) {
Debugger.fatal("AbsActivityHandler.createIntent()应返回的带有ClassName的显式跳转Intent");
callback.onComplete(UriResult.CODE_ERROR);
return;
}
intent.setData(request.getUri());
UriSourceTools.setIntentSource(intent, request);
// 启动Activity
request.putFieldIfAbsent(ActivityLauncher.FIELD_LIMIT_PACKAGE, limitPackage());
int resultCode = RouterComponents.startActivity(request, intent);
// 回调方法
onActivityStartComplete(request, resultCode);
// 完成
callback.onComplete(resultCode);
}
}
Handler URI 分发总结
- uri 先RootUriHandler的handler分发到ChainedHandler的handler
- ChainedHandler通过遍历确定是PageAnnotationHandler,UriAnnotationHandler,RegexAnnotationHandler中的哪个处理
- 通过XXAnnotationHandler获取到PathHandler.
- PathHandler调用最终的Handler。
WMRouter源码分析总结
- WMRouter使用到的技术有SPI思想,使用AutoService 自动生成配置文件,APT(Annotation Process Tool)编译时处理注解技术。使用javapoet 自动生成源码
- WMRouter的Handler分发处理机制是其中心算法,其分发过程类似Android 的触摸事件分发。
- WMRouter虽然实现了activity,fragment的跳转,但是没有对activity和fragment进行管理。因此在实际项目中需要重写相关的Handler实现对activity和fragment的管理。
参考博客
- http://www.hchstudio.cn/article/2018/e164/
- https://www.jianshu.com/p/dd9a2ad6995d
- git路径:https://github.com/meituan/WMRouter.git
- 官方文档介绍:https://tech.meituan.com/2018/08/23/meituan-waimai-android-open-source-routing-framework.html