ServiceLoader模块的使用

ServiceLoader模块使用主要分三步:

  1. 定义Java接口
  2. 注解声明实现类
  3. 加载实现类

1、RouterService注解声明实现类

通过RouterService注解声明实现类所实现的接口(或继承的父类,例如Activity、Fragment、Object等,后文不再重复说明),一个接口可以有多个实现类,一个类也可以同时实现多个接口。RouterService注解的参数如下:

  • interfaces:必选参数。声明实现的接口,可配置多个。
  • key:可选参数。同一接口的不同实现类,通过唯一的key进行区分。
  • singleton:可选参数。声明实现类是否为单例,默认为false。

示例如下:

  1. public interface IService {
  2. }
  3. @RouterService(interfaces = IService.class, key = 'key1')
  4. public static class ServiceImpl1 implements IService {
  5. }
  6. @RouterService(interfaces = IService.class, key = 'key2', singleton = true)
  7. public static class ServiceImpl2 implements IService {
  8. }

2、获取实现类的Class

可以直接获取实现类的Class,例如获取Activity的Class进行页面跳转。

2.1 指定接口和Key,获取某个实现类的Class(要求注解声明时指定了Key)

  1. Class<IService> clazz = Router.getServiceClass(IService.class, "key1");

2.2 指定接口,获取注解声明的所有实现类的Class

  1. List<Class<IService>> classes = Router.getAllServiceClasses(IService.class);

3、获取实现类的实例

ServiceLoader更常见的使用场景,是获取实现类的实例而不是Class。实现类的构造在ServiceLoader中最终由Factory实现,构造失败会返回null或空数组。

3.1 无参数构造

  1. // 使用无参构造函数
  2. IService service = Router.getService(IService.class, "key1");
  3. List<IService> list = Router.getAllServices(IService.class);

3.2 Context参数构造

  1. // 使用Context参数构造
  2. IService service = Router.getService(IService.class, context);
  3. List<IService> list = Router.getAllServices(IService.class, context);

3.3 自定义Factory通过反射构造

对于实现类有特殊构造函数的情况,可以通过Factory自行从class获取构造方法进行构造,示例如下:

  1. // 使用自定义Factory
  2. IFactory factory = new IFactory() {
  3. public Object create(Class clazz) {
  4. return clazz.getConstructor().newInstance();
  5. }
  6. };
  7. IService service = Router.getService(IService.class, factory);
  8. List<IService> list = Router.getAllServices(IService.class, factory);

3.4 使用Provider提供实例

在声明实现类时,可以在类中定义一个返回值类型为该实现类且无参数的静态方法,并使用RouterProvider注解标注。当调用Router获取实例时,如果没有指定Factory,则优先调用Provider方法获取实例,找不到Provider再使用无参数构造。使用示例如下:

  1. @RouterService(interfaces = IService.class, key = 'key', singleton = true)
  2. public static class ServiceImpl implements IService {
  3. public static final ServiceImpl INSTANCE = new ServiceImpl();
  4. // 使用注解声明该方法是一个Provider
  5. @RouterProvider
  6. public static ServiceImpl provideInstance() {
  7. return INSTANCE;
  8. }
  9. }
  10. // 调用时不传Factory,优先找Provider,找不到再使用无参数构造
  11. IService service = Router.getService(IService.class, "key");
  12. List<IService> list = Router.getAllServices(IService.class);

3.5 singleton参数说明

注解声明为singleton的单例实现类,在调用getService()/getAllServices()方式获取实例时,实例会由单例缓存池管理,WMRouter中不会重复构造,且线程安全。

注意:当通过ServiceLoader获取Class、直接调用等其他方式使用实现类时,应避免重复创建对象,否则会导致单例失效。可以结合Provider确保实例不会重复创建。

4、方法调用

利用ServiceLoader可以实现方法调用。

WMRouter的method包中提供了通用的Function接口Func0 ~ Func9、FuncN,分别表示参数为0~9或可变参数的方法。声明方法时应该实现Function接口,示例如下。对于调用次数较多的方法,建议声明为singleton,避免每次调用时重复创建。

  1. @RouterService(interfaces = Func2.class, key = "/add", singleton = true)
  2. public class AddMethod implements Func2<Integer, Integer, Integer> {
  3. @Override
  4. public Integer call(Integer a, Integer b) {
  5. return a + b;
  6. }
  7. }

方法的调用示例如下:

  1. Func2<Integer, Integer, Integer> addMethod = Router.getService(Func2.class, "/add");
  2. Integer result = addMethod.call(1, 2);

也可以直接通过callMethod调用,根据参数个数匹配对应的Function接口。

  1. Integer result = Router.callMethod("/add", 1, 2);