ServiceLoader模块的使用
ServiceLoader模块使用主要分三步:
- 定义Java接口
- 注解声明实现类
- 加载实现类
1、RouterService注解声明实现类
通过RouterService注解声明实现类所实现的接口(或继承的父类,例如Activity、Fragment、Object等,后文不再重复说明),一个接口可以有多个实现类,一个类也可以同时实现多个接口。RouterService注解的参数如下:
- interfaces:必选参数。声明实现的接口,可配置多个。
- key:可选参数。同一接口的不同实现类,通过唯一的key进行区分。
- singleton:可选参数。声明实现类是否为单例,默认为false。
示例如下:
public interface IService {
}
@RouterService(interfaces = IService.class, key = 'key1')
public static class ServiceImpl1 implements IService {
}
@RouterService(interfaces = IService.class, key = 'key2', singleton = true)
public static class ServiceImpl2 implements IService {
}
2、获取实现类的Class
可以直接获取实现类的Class,例如获取Activity的Class进行页面跳转。
2.1 指定接口和Key,获取某个实现类的Class(要求注解声明时指定了Key)
Class<IService> clazz = Router.getServiceClass(IService.class, "key1");
2.2 指定接口,获取注解声明的所有实现类的Class
List<Class<IService>> classes = Router.getAllServiceClasses(IService.class);
3、获取实现类的实例
ServiceLoader更常见的使用场景,是获取实现类的实例而不是Class。实现类的构造在ServiceLoader中最终由Factory实现,构造失败会返回null或空数组。
3.1 无参数构造
// 使用无参构造函数
IService service = Router.getService(IService.class, "key1");
List<IService> list = Router.getAllServices(IService.class);
3.2 Context参数构造
// 使用Context参数构造
IService service = Router.getService(IService.class, context);
List<IService> list = Router.getAllServices(IService.class, context);
3.3 自定义Factory通过反射构造
对于实现类有特殊构造函数的情况,可以通过Factory自行从class获取构造方法进行构造,示例如下:
// 使用自定义Factory
IFactory factory = new IFactory() {
public Object create(Class clazz) {
return clazz.getConstructor().newInstance();
}
};
IService service = Router.getService(IService.class, factory);
List<IService> list = Router.getAllServices(IService.class, factory);
3.4 使用Provider提供实例
在声明实现类时,可以在类中定义一个返回值类型为该实现类且无参数的静态方法,并使用RouterProvider注解标注。当调用Router获取实例时,如果没有指定Factory,则优先调用Provider方法获取实例,找不到Provider再使用无参数构造。使用示例如下:
@RouterService(interfaces = IService.class, key = 'key', singleton = true)
public static class ServiceImpl implements IService {
public static final ServiceImpl INSTANCE = new ServiceImpl();
// 使用注解声明该方法是一个Provider
@RouterProvider
public static ServiceImpl provideInstance() {
return INSTANCE;
}
}
// 调用时不传Factory,优先找Provider,找不到再使用无参数构造
IService service = Router.getService(IService.class, "key");
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,避免每次调用时重复创建。
@RouterService(interfaces = Func2.class, key = "/add", singleton = true)
public class AddMethod implements Func2<Integer, Integer, Integer> {
@Override
public Integer call(Integer a, Integer b) {
return a + b;
}
}
方法的调用示例如下:
Func2<Integer, Integer, Integer> addMethod = Router.getService(Func2.class, "/add");
Integer result = addMethod.call(1, 2);
也可以直接通过callMethod
调用,根据参数个数匹配对应的Function接口。
Integer result = Router.callMethod("/add", 1, 2);