WMRouter源码剖析

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的多个模块之间通过接口调用代码,实现模块解耦,便于实现组件化、模块间通信,以及和依赖注入类似的功能等。其特点如下:

  1. 使用注解自动配置
  2. 支持获取接口的所有实现,或根据Key获取特定实现
  3. 支持获取Class或获取实例
  4. 支持无参构造、Context构造,或自定义Factory、Provider构造
  5. 支持单例管理
  6. 支持方法调用

基本实现

数据结构

根据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和实现的接口类来获取实现。

    1. 简单的调用
        /**
         * 创建指定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);
        }
    
    1. 通过这个来实现调用实现的方法

          /**
           * 调用方法。方法应该实现 {@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链接的跳转等场景,特点如下:

  1. 支持多scheme、host、path
  2. 支持URI正则匹配
  3. 页面配置支持Java代码动态注册,或注解配置自动注册
  4. 支持配置全局和局部拦截器,可在跳转前执行同步/异步操作,例如定位、登录等
  5. 支持单次跳转特殊操作:Intent设置Extra/Flags、设置跳转动画、自定义StartActivity操作等
  6. 支持页面Exported控制,特定页面不允许外部跳转
  7. 支持配置全局和局部降级策略
  8. 支持配置单次和全局跳转监听
  9. 完全组件化设计,核心组件均可扩展、按需组合,实现灵活强大的功能

本质上通过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, "单例标识");
    }
}

通过以上源码分析可以获取到的数据存储结构是:

  1. 处理RouterUri的handler存储在private final Map<String, PathHandler> mMap;key值是uri,value值是PathHandler。
  2. 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

对以上部分进行小结:

  1. interfaces 模块主要是提供了注解和ServiceImpl这个数据结构。
  2. compiler 主要功能是提供了对注解的解析,并且生成java文件。

plugin的主要功能:

  1. 提供debug调试的开关.
  2. 将注解生成器生成的初始化类汇总到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

初始化
  1. 初始化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();
            }
        }
    
    1. 初始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();
  }
}

由初始化过程可以知道:

  1. 通过ServiceLoader.java的初始,将IUriAnnotationInit.class 和UriAnnotationInit_xxx的ServerImpl对应起来
  2. 通过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());
    }
}

根据调用顺序

  1. Router#startUri
  2. ChainedHandler#handle,继承父类的UriHandler#handle
  3. ChainedHandler#handleInternal,最终调用到ChainedHandler#next
  4. 通过遍历处理获调用UriAnnotationHandler#handleInternal,根据uri获取PathHandler
  5. 调用pathHandler#handle,继承父类uriHandler#handle。
  6. 根据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 分发总结
  1. uri 先RootUriHandler的handler分发到ChainedHandler的handler
  2. ChainedHandler通过遍历确定是PageAnnotationHandler,UriAnnotationHandler,RegexAnnotationHandler中的哪个处理
  3. 通过XXAnnotationHandler获取到PathHandler.
  4. PathHandler调用最终的Handler。

WMRouter源码分析总结

  1. WMRouter使用到的技术有SPI思想,使用AutoService 自动生成配置文件,APT(Annotation Process Tool)编译时处理注解技术。使用javapoet 自动生成源码
  2. WMRouter的Handler分发处理机制是其中心算法,其分发过程类似Android 的触摸事件分发。
  3. 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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值