模块化开发中,模块之间跨模块进行服务调用,获取其他服务的功能是一种常见的现象。
例如,模块A、B、C分别提供了Service A、B、C,模块A、B、C均依赖于base模块,然后再base模块里面定义了Service A、B、C各自实现的接口InterfaceA、B、C。此时模块A想要调用模块B的Service,因为模块A、B间相互不依赖,所以需要通过base模块中提供的InterfaceB来进行服务的获取。怎么通过InterfaceB获取到ServiceB的实例,进而使用其提供的服务呢?
我们可以知道,因为各个模块最终都会打包到主工程中,如果我们知道要使用的服务的全限定类名,就可以通过反射来实例化具体对象。但是这样初始化一个实例需要保证被实例化的那个服务类保持不变,而且获得的对象是一个新的实例,如果各个模块对于服务有各自的初始化逻辑,或者业务过程中有不同的配置,那这样的服务是不能满足需求的。
如果可以根据base模块中的Interface作为key获取到对应模块中的Service,然后调用具体的功能就好了。这样子就不需要依赖反射提供的全限定类名来实例化,也可以获取经过配置的服务实例。
答案就是APT。
首先定义一个需要被APT识别的注解。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 声明一个ServiceLoader,通过interface和key加载实现类。此注解可以用在任意静态类上。
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface IServiceLoader {
/**
* 实现的接口(或继承的父类)
*/
Class[] interfaces();
/**
* 同一个接口的多个实现类之间,可以通过唯一的key区分。
*/
String[] key() default {};
/**
* 是否为单例。如果是单例,则使用ServiceLoader.getService不会重复创建实例。
*/
boolean singleton() default false;
/**
* 是否设置为默认实现类。如果是默认实现类,则在获取该实现类实例时可以不指定key
*/
boolean defaultImpl() default false;
}
然后通过解析器解析具有这个注解的Service。
import com.google.auto.service.AutoService;
import com.sun.tools.javac.code.Symbol;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.MirroredTypesException;
import javax.lang.model.type.TypeMirror;
//核心的注解处理类,在这里我们可以扫描源代码里所有的注解,找到我们需要的注解,然后做出相应处理
@AutoService(Processor.class)
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class ServiceAnnotationProcessor extends BaseProcessor {
/**
* interfaceClass --> Entity7
*/
private final HashMap<String, Entity> mEntityMap = new HashMap<>();
private String mHash = null;
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
if (env.processingOver()) {
generateInitClass();//实例化注解类
} else {
processAnnotations(env);//解析注解
}
return true;
}
private void processAnnotations(RoundEnvironment env) {
for (Element element : env.getElementsAnnotatedWith(IServiceLoader.class)) {
if (!(element instanceof Symbol.ClassSymbol)) {
continue;
}
Symbol.ClassSymbol cls = (Symbol.ClassSymbol) element;
if (mHash == null) {
mHash = hash(cls.className());
}
IServiceLoader service = cls.getAnnotation(IServiceLoader.class);
if (service == null) {
continue;
}
List<? extends TypeMirror> typeMirrors = getInterface(service);
String[] keys = service.key();
String implementationName = cls.className();
boolean singleton = service.singleton();
final boolean defaultImpl = service.defaultImpl();
if (typeMirrors != null && !typeMirrors.isEmpty()) {
for (TypeMirror mirror : typeMirrors) {
if (mirror == null) {
continue;
}
if (!isConcreteSubType(cls, mirror)) {
String msg = cls.className() + "没有实现注解" + IServiceLoader.class.getName()
+ "标注的接口" + mirror.toString();
throw new RuntimeException(msg);
}
String interfaceName = getClassName(mirror);
Entity entity = mEntityMap.get(interfaceName);
if (entity == null) {
entity = new Entity(interfaceName);
mEntityMap.put(interfaceName, entity);
}
if (defaultImpl) {
//如果设置为默认实现,则手动添加一个内部标识默认实现的key
entity.put(ServiceImpl.DEFAULT_IMPL_KEY, implementationName, singleton);
}
if (keys.length > 0) {
for (String key : keys) {
if (key.contains(":")) {
String msg = String.format("%s: 注解%s的key参数不可包含冒号",
implementationName, IServiceLoader.class.getName());
throw new RuntimeException(msg);
}
entity.put(key, implementationName, singleton);
}
} else {
entity.put(null, implementationName, singleton);
}
}
}
}
}
private void generateInitClass() {
if (mEntityMap.isEmpty() || mHash == null) {
return;
}
ServiceInitClassBuilder generator = new ServiceInitClassBuilder("ServiceInit" + Const.SPLITTER + mHash);
for (Map.Entry<String, Entity> entry : mEntityMap.entrySet()) {
for (ServiceImpl service : entry.getValue().getMap().values()) {
generator.put(entry.getKey(), service.getKey(), service.getImplementation(), service.isSingleton());
}
}
generator.build();
}
private static List<? extends TypeMirror> getInterface(IServiceLoader service) {
try {
service.interfaces();
} catch (MirroredTypesException mte) {
return mte.getTypeMirrors();
}
return null;
}
@Override
public Set<String> getSupportedAnnotationTypes() {
return new HashSet<>(Collections.singletonList(IServiceLoader.class.getName()));
}
public static class Entity {
private final String mInterfaceName;
private final Map<String, ServiceImpl> mMap = new HashMap<>();
public Entity(String interfaceName) {
mInterfaceName = interfaceName;
}
public Map<String, ServiceImpl> getMap() {
return mMap;
}
public void put(String key, String implementationName, boolean singleton) {
if (implementationName == null) {
return;
}
ServiceImpl impl = new ServiceImpl(key, implementationName, singleton);
ServiceImpl prev = mMap.put(impl.getKey(), impl);
String errorMsg = ServiceImpl.checkConflict(mInterfaceName, prev, impl);
if (errorMsg != null) {
throw new RuntimeException(errorMsg);
}
}
public List<String> getContents() {
List<String> list = new ArrayList<>();
for (ServiceImpl impl : mMap.values()) {
list.add(impl.toConfig());
}
return list;
}
}
}
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Type;
import java.io.IOException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.UUID;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
public abstract class BaseProcessor extends AbstractProcessor {
protected Filer filer;
protected Types types;
protected Elements elements;
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
filer = processingEnvironment.getFiler();
types = processingEnvironment.getTypeUtils();
elements = processingEnvironment.getElementUtils();
}
/**
* 从字符串获取TypeElement对象
*/
public TypeElement typeElement(String className) {
return elements.getTypeElement(className);
}
/**
* 从字符串获取TypeMirror对象
*/
public TypeMirror typeMirror(String className) {
return typeElement(className).asType();
}
/**
* 从字符串获取ClassName对象
*/
public ClassName className(String className) {
return ClassName.get(typeElement(className));
}
/**
* 从字符串获取TypeName对象,包含Class的泛型信息
*/
public TypeName typeName(String className) {
return TypeName.get(typeMirror(className));
}
public static String getClassName(TypeMirror typeMirror) {
return typeMirror == null ? "" : typeMirror.toString();
}
public boolean isSubType(TypeMirror type, String className) {
return type != null && types.isSubtype(type, typeMirror(className));
}
public boolean isSubType(Element element, String className) {
return element != null && isSubType(element.asType(), className);
}
public boolean isSubType(Element element, TypeMirror typeMirror) {
return element != null && types.isSubtype(element.asType(), typeMirror);
}
/**
* 非抽象类
*/
public boolean isConcreteType(Element element) {
return element instanceof TypeElement && !element.getModifiers().contains(
Modifier.ABSTRACT);
}
/**
* 非抽象子类
*/
public boolean isConcreteSubType(Element element, String className) {
return isConcreteType(element) && isSubType(element, className);
}
/**
* 非抽象子类
*/
public boolean isConcreteSubType(Element element, TypeMirror typeMirror) {
return isConcreteType(element) && isSubType(element, typeMirror);
}
public boolean isInterceptor(Element element) {
return isConcreteSubType(element, Const.URI_INTERCEPTOR_CLASS);
}
public static String randomHash() {
return hash(UUID.randomUUID().toString());
}
public static String hash(String str) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(str.getBytes());
return new BigInteger(1, md.digest()).toString(16);
} catch (NoSuchAlgorithmException e) {
return Integer.toHexString(str.hashCode());
}
}
/**
* 创建Handler。格式:<code>"com.demo.TestActivity"</code> 或 <code>new TestHandler()</code>
*/
public CodeBlock buildHandler(boolean isActivity, Symbol.ClassSymbol cls) {
CodeBlock.Builder b = CodeBlock.builder();
if (isActivity) {
b.add("$S", cls.className());
} else {
b.add("new $T()", cls);
}
return b.build();
}
/**
* 创建Interceptors。格式:<code>, new Interceptor1(), new Interceptor2()</code>
*/
public CodeBlock buildInterceptors(List<? extends TypeMirror> interceptors) {
CodeBlock.Builder b = CodeBlock.builder();
if (interceptors != null && interceptors.size() > 0) {
for (TypeMirror type : interceptors) {
if (type instanceof Type.ClassType) {
Symbol.TypeSymbol e = ((Type.ClassType) type).asElement();
if (e instanceof Symbol.ClassSymbol && isInterceptor(e)) {
b.add(", new $T()", e);
}
}
}
}
return b.build();
}
/**
* 生成类似下面格式的HandlerInitClass,同时生成ServiceInitClass
* <pre>
* package com.sankuai.waimai.router.generated;
* public class UriRouter_RouterUri_xxx implements IUriAnnotationInit {
* public void init(UriAnnotationHandler handler) {
* handler.register("", "", "/login", "com.xxx.LoginActivity", false);
* // ...
* }
* }
* </pre>
*
* @param code 方法中的代码
* @param genClassName 生成class的SimpleClassName,形如 UriRouter_RouterUri_xxx
* @param handlerClassName Handler类名,例如 com.sankuai.waimai.router.common.UriAnnotationHandler
* @param interfaceName 接口名,例如 com.sankuai.waimai.router.common.IUriAnnotationInit
*/
public void buildHandlerInitClass(CodeBlock code, String genClassName, String handlerClassName, String interfaceName) {
MethodSpec methodSpec = MethodSpec.methodBuilder(Const.INIT_METHOD)
.addModifiers(Modifier.PUBLIC)
.returns(TypeName.VOID)
.addParameter(className(handlerClassName), "handler")
.addCode(code)
.build();
TypeSpec typeSpec = TypeSpec.classBuilder(genClassName)
.addSuperinterface(className(interfaceName))
.addModifiers(Modifier.PUBLIC)
.addMethod(methodSpec)
.build();
try {
JavaFile.builder(Const.GEN_PKG, typeSpec)
.build()
.writeTo(filer);
} catch (IOException e) {
throw new RuntimeException(e);
}
String fullImplName = Const.GEN_PKG + Const.DOT + genClassName;
String className = "ServiceInit" + Const.SPLITTER + hash(genClassName);
new ServiceInitClassBuilder(className)
.putDirectly(interfaceName, fullImplName, fullImplName, false)
.build();
}
/**
* 辅助工具类,用于生成ServiceInitClass,格式如下:
* <pre>
* package com.midea.base.serviceloader.api.generated.service;
*
* import com.midea.base.serviceloader.api.service.ServiceLoader;
*
* public class <ClassName> {
* public static void init() {
* ServiceLoader.put(com.xxx.interface1.class, "key1", com.xxx.implementsA.class, false);
* ServiceLoader.put(com.xxx.interface2.class, "key2", com.xxx.implementsB.class, false);
* }
* }
* </pre>
*/
public class ServiceInitClassBuilder {
private final String className;
private final CodeBlock.Builder builder;
private final ClassName serviceLoaderClass;
public ServiceInitClassBuilder(String className) {
this.className = className;
this.builder = CodeBlock.builder();
this.serviceLoaderClass = className(Const.SERVICE_LOADER_CLASS);
}
public ServiceInitClassBuilder put(String interfaceName, String key, String implementName, boolean singleton) {
builder.addStatement("$T.put($T.class, $S, $T.class, $L)",
serviceLoaderClass,
className(interfaceName),
key,
className(implementName),
singleton);
return this;
}
public ServiceInitClassBuilder putDirectly(String interfaceName, String key, String implementName, boolean singleton) {
// implementName是注解生成的类,直接用$L拼接原始字符串
builder.addStatement("$T.put($T.class, $S, $L.class, $L)",
serviceLoaderClass,
className(interfaceName),
key,
implementName,
singleton);
return this;
}
public void build() {
MethodSpec methodSpec = MethodSpec.methodBuilder(Const.INIT_METHOD)
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(TypeName.VOID)
.addCode(this.builder.build())
.build();
TypeSpec typeSpec = TypeSpec.classBuilder(this.className)
.addModifiers(Modifier.PUBLIC)
.addMethod(methodSpec)
.build();
try {
JavaFile.builder(Const.GEN_PKG_SERVICE, typeSpec)
.build()
.writeTo(filer);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
public class Const {
private static final String PKG = "com.zpw.base.core.serviceloader.api.";
public static final String NAME = "MIDEA_BASE";
// 生成的代码
public static final String GEN_PKG = PKG + "generated";
public static final String GEN_PKG_SERVICE = GEN_PKG + ".service";
public static final String SPLITTER = "_";
/**
* ServiceLoader初始化
*/
public static final String SERVICE_LOADER_INIT = GEN_PKG + ".ServiceLoaderInit";
public static final char DOT = '.';
public static final String INIT_METHOD = "init";
public static final String URI_INTERCEPTOR_CLASS = PKG + "core.UriInterceptor";
public static final String SERVICE_LOADER_CLASS = PKG + "service.ServiceLoader";
}
通过APT解析注解之后,我们会生成如下Java文件。可见这个实现类将Interface和对应的服务实现类保存了起来。
package com.zpw.base.core.serviceloader.api.generated.service;
import com.example.myapplication.ConfigMoaService;
import com.example.myapplication.IConfigMoa;
import com.midea.base.core.serviceloader.api.service.ServiceLoader;
public class ServiceInit_a8270c82eb44fbd3083fd91dd2fce7ef {
public static void init() {
ServiceLoader.put(IConfigMoa.class, "com.example.myapplication.ConfigMoaService", ConfigMoaService.class, true);
ServiceLoader.put(IConfigMoa.class, "_service_default_impl", ConfigMoaService.class, true);
}
}
这里面的SeviceLoader其实是一个容器。
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.midea.base.core.serviceloader.annotation.interfaces.Const;
import com.midea.base.core.serviceloader.annotation.service.ServiceImpl;
import com.midea.base.core.serviceloader.api.components.RouterComponents;
import com.midea.base.core.serviceloader.api.core.Debugger;
import com.midea.base.core.serviceloader.api.utils.LazyInitHelper;
import com.midea.base.core.serviceloader.api.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获取实现类
* @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 IServiceProvider} 方法或无参数构造。对于声明了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 IServiceProvider} 方法或无参数构造。对于声明了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";
}
}
}
这里面用ServiceImpl封装了服务对应的参数。
import java.util.Objects;
/**
* Service的一个实现
*/
public class ServiceImpl {
private static final String SPLITTER = ":";
private static final String SINGLETON = "singleton";
public static final String DEFAULT_IMPL_KEY = "_service_default_impl";
public static String checkConflict(String interfaceName, ServiceImpl impl, ServiceImpl previous) {
if (impl != null && previous != null && !stringEquals(previous.implementation, impl.implementation)) {
if (DEFAULT_IMPL_KEY.equals(impl.getKey())) {
return String.format("接口%s 的默认实现只允许存在一个\n目前存在多个默认实现: %s, %s", interfaceName, previous, impl);
} else {
return String.format("接口%s对应key='%s'存在多个实现: %s, %s", interfaceName, impl.getKey(), previous, impl);
}
}
return null;
}
private static boolean stringEquals(String s1, String s2) {
return Objects.equals(s1, s2);
}
private static boolean isEmpty(String key) {
return key == null || key.length() == 0;
}
private final String key;
private final String implementation;
private final Class implementationClazz;
private final boolean singleton;
public ServiceImpl(String key, Class implementation, boolean singleton) {
if (key == null || implementation == null) {
throw new RuntimeException("key和implementation不应该为空");
}
this.key = key;
this.implementation = "";
this.implementationClazz = implementation;
this.singleton = singleton;
}
public ServiceImpl(String key, String implementation, boolean singleton) {
if (isEmpty(implementation)) {
throw new RuntimeException("implementation不应该为空");
}
this.key = isEmpty(key) ? implementation : key; // 没有指定key,则为implementation
this.implementation = implementation;
this.implementationClazz = null;
this.singleton = singleton;
}
public String toConfig() {
String s = key + SPLITTER + implementation;
if (singleton) {
s += SPLITTER + SINGLETON;
}
return s;
}
/**
* not null
*/
public String getKey() {
return key;
}
public String getImplementation() {
return implementation;
}
public Class getImplementationClazz() {
return implementationClazz;
}
public boolean isSingleton() {
return singleton;
}
@Override
public String toString() {
return implementation;
}
}
实例化服务类的工厂。
import androidx.annotation.NonNull;
import com.midea.base.core.serviceloader.api.service.DefaultFactory;
import com.midea.base.core.serviceloader.api.service.IFactory;
/**
* 用于配置组件
*/
public class RouterComponents {
@NonNull
private static IFactory sDefaultFactory = DefaultFactory.INSTANCE;
public static void setDefaultFactory(IFactory factory) {
sDefaultFactory = factory == null ? DefaultFactory.INSTANCE : factory;
}
@NonNull
public static IFactory getDefaultFactory() {
return sDefaultFactory;
}
}
import androidx.annotation.NonNull;
import com.midea.base.core.serviceloader.api.utils.ProviderPool;
/**
* 默认的Factory,先尝试Provider,再尝试无参数构造
*/
public class DefaultFactory implements IFactory {
public static final DefaultFactory INSTANCE = new DefaultFactory();
private DefaultFactory() {
}
@NonNull
@Override
public <T> T create(@NonNull Class<T> clazz) throws Exception {
T t = ProviderPool.create(clazz);
if (t != null) {
return t;
} else {
return clazz.newInstance();
}
}
}
import androidx.annotation.NonNull;
/**
* 从Class构造实例
*/
public interface IFactory {
@NonNull
<T> T create(@NonNull Class<T> clazz) throws Exception;
}
初始化工具类。
import android.os.SystemClock;
import com.midea.base.core.serviceloader.api.core.Debugger;
/**
* 初始化辅助工具类。
*
* 一些初始化任务可以在使用时按需初始化(通常在主线程);
* 但也可以提前调用并初始化(通常在后台线程),使用时等待初始化完成。
*/
public abstract class LazyInitHelper {
private final String mTag;
private boolean mHasInit = false;
public LazyInitHelper(String tag) {
mTag = tag;
}
/**
* 此初始化方法的调用不是必须的。
* 使用时会按需初始化;但也可以提前调用并初始化,使用时会等待初始化完成。
* 本方法线程安全。
*/
public void lazyInit() {
performInit();
}
/**
* 使用时确保已经初始化;如果正在初始化,则等待完成。
*/
public void ensureInit() {
performInit();
}
private void performInit() {
if (!mHasInit) {
synchronized (this) {
if (!mHasInit) {
long ts = 0;
final boolean enableLog = Debugger.isEnableLog();
if (enableLog) {
ts = SystemClock.uptimeMillis();
}
try {
doInit();
mHasInit = true;
} catch (Throwable t) {
Debugger.fatal(t);
}
if (enableLog) {
Debugger.i("%s init cost %s ms", mTag,
SystemClock.uptimeMillis() - ts);
}
}
}
}
}
protected abstract void doInit();
}
单例缓存。
package com.midea.base.core.serviceloader.api.utils;
import androidx.annotation.NonNull;
import com.midea.base.core.serviceloader.api.service.IFactory;
import java.util.HashMap;
import java.util.Map;
/**
* 单例缓存
*/
public class SingletonPool {
private static final Map<Class, Object> CACHE = new HashMap<>();
@SuppressWarnings("unchecked")
public static <I, T extends I> T get(Class<I> clazz, IFactory factory) throws Exception {
if (clazz == null) {
return null;
}
if (factory == null) {
factory = RouterComponents.getDefaultFactory();
}
Object instance = getInstance(clazz, factory);
Debugger.i("[SingletonPool] get instance of class = %s, result = %s", clazz, instance);
return (T) instance;
}
@NonNull
private static Object getInstance(@NonNull Class clazz, @NonNull IFactory factory) throws Exception {
Object t = CACHE.get(clazz);
if (t != null) {
return t;
} else {
synchronized (CACHE) {
t = CACHE.get(clazz);
if (t == null) {
Debugger.i("[SingletonPool] >>> create instance: %s", clazz);
t = factory.create(clazz);
//noinspection ConstantConditions
if (t != null) {
CACHE.put(clazz, t);
}
}
}
return t;
}
}
}
通过上面的APT操作,我们将各个模块需要提供给外界使用的Service都保存起来了,这时候需要将它们汇总并初始化。这时候需要使用Tramsform。使用插件来执行最后的逻辑。
import com.android.build.gradle.BaseExtension;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
/**
* 插件所做工作:将注解生成器生成的初始化类汇总到ServiceLoaderInit,运行时直接调用ServiceLoaderInit
*/
public class ServiceLoaderPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
WMRouterExtension extension = project.getExtensions().create(Const.NAME, WMRouterExtension.class);
WMRouterLogger.info("register transform");
project.getExtensions().findByType(BaseExtension.class).registerTransform(new WMRouterTransform());
project.afterEvaluate(p -> WMRouterLogger.setConfig(extension));
}
}
public class WMRouterExtension {
/**
* 出错时中断编译
*/
private boolean abortOnError = true;
/**
* 是否允许Log
*/
private boolean enableLog = true;
/**
* 是否开启Debug。Debug模式会输出更详细的Log。
*/
private boolean enableDebug = false;
public void setAbortOnError(boolean abortOnError) {
this.abortOnError = abortOnError;
}
public boolean getAbortOnError() {
return abortOnError;
}
public void setEnableLog(boolean enableLog) {
this.enableLog = enableLog;
}
public boolean getEnableLog() {
return enableLog;
}
public void setEnableDebug(boolean enableDebug) {
this.enableDebug = enableDebug;
}
public boolean getEnableDebug() {
return enableDebug;
}
}
public class WMRouterLogger {
private static final String PREFIX = "[SERVICE_LOADER_PLUGIN] ";
private static boolean sEnableLog = false;
private static boolean sEnableDebug = false;
private static boolean sAbortOnError = false;
public static void setConfig(WMRouterExtension extension) {
sEnableDebug = extension.getEnableDebug();
sEnableLog = extension.getEnableLog() || extension.getEnableDebug();
sAbortOnError = extension.getAbortOnError();
}
public static void debug(String s, Object... args) {
if (sEnableDebug) {
System.out.println(format(s, args));
}
}
public static void info(String s, Object... args) {
if (sEnableLog) {
System.out.println(format(s, args));
}
}
public static void warn(String s, Object... args) {
if (sEnableLog) {
System.err.println(format(s, args));
}
}
public static void error(String s, Object... args) {
if (sEnableLog) {
System.err.println(format(s, args));
}
}
public static void error(Throwable t) {
if (sEnableLog) {
t.printStackTrace();
}
}
public static void fatal(Throwable t) {
if (sAbortOnError) {
if (t instanceof RuntimeException) {
throw ((RuntimeException) t);
} else {
throw new RuntimeException(t);
}
} else {
t.printStackTrace();
}
}
public static void fatal(String s, Object... args) {
fatal(new RuntimeException(format(s, args)));
}
private static String format(String s, Object... args) {
return PREFIX + (args.length == 0 ? s : String.format(s, args));
}
}
package com.midea.base.core.serviceloader.plugin;
import com.android.SdkConstants;
import com.android.build.api.transform.Format;
import com.android.build.api.transform.QualifiedContent;
import com.android.build.api.transform.Transform;
import com.android.build.api.transform.TransformInput;
import com.android.build.api.transform.TransformInvocation;
import com.android.build.gradle.internal.pipeline.TransformManager;
import com.google.common.collect.ImmutableSet;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOCase;
import org.apache.commons.io.filefilter.SuffixFileFilter;
import org.apache.commons.io.filefilter.TrueFileFilter;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class WMRouterTransform extends Transform {
private static final String TRANSFORM = "Transform: ";
private static final String GENERATE_INIT = "GenerateInit: ";
/**
* Linux/Unix: com/sankuai/waimai/router/generated/service
* Windows: com\sankuai\waimai\router\generated\service
*/
public static final String INIT_SERVICE_DIR = Const.GEN_PKG_SERVICE.replace('.', File.separatorChar);
/**
* com/sankuai/waimai/router/generated/service
*/
public static final String INIT_SERVICE_PATH = Const.GEN_PKG_SERVICE.replace('.', '/');
@Override
public String getName() {
return Const.NAME;
}
@Override
public Set<QualifiedContent.ContentType> getInputTypes() {
return TransformManager.CONTENT_CLASS;
}
@Override
public Set<? super QualifiedContent.Scope> getScopes() {
return TransformManager.SCOPE_FULL_PROJECT;
}
@Override
public boolean isIncremental() {
return true;
}
@Override
public void transform(TransformInvocation invocation) {
WMRouterLogger.info(TRANSFORM + "start...");
long ms = System.currentTimeMillis();
Set<String> initClasses = Collections.newSetFromMap(new ConcurrentHashMap<>());
for (TransformInput input : invocation.getInputs()) {
input.getJarInputs().parallelStream().forEach(jarInput -> {
File src = jarInput.getFile();
File dst = invocation.getOutputProvider().getContentLocation(
jarInput.getName(), jarInput.getContentTypes(), jarInput.getScopes(),
Format.JAR);
try {
scanJarFile(src, initClasses);
FileUtils.copyFile(src, dst);
} catch (IOException e) {
throw new RuntimeException(e);
}
});
input.getDirectoryInputs().parallelStream().forEach(directoryInput -> {
File src = directoryInput.getFile();
File dst = invocation.getOutputProvider().getContentLocation(
directoryInput.getName(), directoryInput.getContentTypes(),
directoryInput.getScopes(), Format.DIRECTORY);
try {
scanDir(src, initClasses);
FileUtils.copyDirectory(src, dst);
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}
File dest = invocation.getOutputProvider().getContentLocation(
"WMRouter", TransformManager.CONTENT_CLASS,
ImmutableSet.of(QualifiedContent.Scope.PROJECT), Format.DIRECTORY);
generateServiceInitClass(dest.getAbsolutePath(), initClasses);
WMRouterLogger.info(TRANSFORM + "cost %s ms", System.currentTimeMillis() - ms);
}
/**
* 扫描由注解生成器生成到包 {@link Const#GEN_PKG_SERVICE} 里的初始化类
*/
private void scanJarFile(File file, Set<String> initClasses) throws IOException {
JarFile jarFile = new JarFile(file);
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
String name = entry.getName();
if (name.endsWith(SdkConstants.DOT_CLASS) && name.startsWith(INIT_SERVICE_PATH)) {
String className = trimName(name, 0).replace('/', '.');
initClasses.add(className);
WMRouterLogger.info(" find ServiceInitClass: %s", className);
}
}
}
/**
* 扫描由注解生成器生成到包 {@link Const#GEN_PKG_SERVICE} 里的初始化类
*/
private void scanDir(File dir, Set<String> initClasses) throws IOException {
File packageDir = new File(dir, INIT_SERVICE_DIR);
if (packageDir.exists() && packageDir.isDirectory()) {
Collection<File> files = FileUtils.listFiles(packageDir,
new SuffixFileFilter(SdkConstants.DOT_CLASS, IOCase.INSENSITIVE), TrueFileFilter.INSTANCE);
for (File f : files) {
String className = trimName(f.getAbsolutePath(), dir.getAbsolutePath().length() + 1)
.replace(File.separatorChar, '.');
initClasses.add(className);
WMRouterLogger.info(" find ServiceInitClass: %s", className);
}
}
}
/**
* [prefix]com/xxx/aaa.class --> com/xxx/aaa
* [prefix]com\xxx\aaa.class --> com\xxx\aaa
*/
private String trimName(String s, int start) {
return s.substring(start, s.length() - SdkConstants.DOT_CLASS.length());
}
/**
* 生成格式如下的代码,其中ServiceInit_xxx由注解生成器生成。
* <pre>
* package com.sankuai.waimai.router.generated;
*
* public class ServiceLoaderInit {
*
* public static void init() {
* ServiceInit_xxx1.init();
* ServiceInit_xxx2.init();
* }
* }
* </pre>
*/
private void generateServiceInitClass(String directory, Set<String> classes) {
if (classes.isEmpty()) {
WMRouterLogger.info(GENERATE_INIT + "skipped, no service found");
return;
}
try {
WMRouterLogger.info(GENERATE_INIT + "start...");
long ms = System.currentTimeMillis();
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
ClassVisitor cv = new ClassVisitor(Opcodes.ASM5, writer) {
};
String className = Const.SERVICE_LOADER_INIT.replace('.', '/');
cv.visit(50, Opcodes.ACC_PUBLIC, className, null, "java/lang/Object", null);
MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
Const.INIT_METHOD, "()V", null, null);
mv.visitCode();
for (String clazz : classes) {
mv.visitMethodInsn(Opcodes.INVOKESTATIC, clazz.replace('.', '/'),
"init",
"()V",
false);
}
mv.visitMaxs(0, 0);
mv.visitInsn(Opcodes.RETURN);
mv.visitEnd();
cv.visitEnd();
File dest = new File(directory, className + SdkConstants.DOT_CLASS);
dest.getParentFile().mkdirs();
new FileOutputStream(dest).write(writer.toByteArray());
WMRouterLogger.info(GENERATE_INIT + "cost %s ms", System.currentTimeMillis() - ms);
} catch (IOException e) {
WMRouterLogger.fatal(e);
}
}
}
通过Tramsfrom会生成一下文件。
package com.midea.base.core.serviceloader.api.generated;
import com.midea.base.core.serviceloader.api.generated.service.ServiceInit_a8270c82eb44fbd3083fd91dd2fce7ef;
public class ServiceLoaderInit {
public static void init() {
ServiceInit_a8270c82eb44fbd3083fd91dd2fce7ef.init();
}
}
然后我们向外界提供一个服务获取类。
import android.content.Context;
import android.os.Looper;
import android.util.Log;
import com.midea.base.core.serviceloader.annotation.IServiceLoader;
import com.midea.base.core.serviceloader.annotation.IServiceProvider;
import com.midea.base.core.serviceloader.annotation.service.ServiceImpl;
import com.midea.base.core.serviceloader.api.core.Debugger;
import com.midea.base.core.serviceloader.api.exception.DefaultServiceException;
import com.midea.base.core.serviceloader.api.method.Func0;
import com.midea.base.core.serviceloader.api.method.Func1;
import com.midea.base.core.serviceloader.api.method.Func2;
import com.midea.base.core.serviceloader.api.method.Func3;
import com.midea.base.core.serviceloader.api.method.Func4;
import com.midea.base.core.serviceloader.api.method.Func5;
import com.midea.base.core.serviceloader.api.method.Func6;
import com.midea.base.core.serviceloader.api.method.Func7;
import com.midea.base.core.serviceloader.api.method.Func8;
import com.midea.base.core.serviceloader.api.method.Func9;
import com.midea.base.core.serviceloader.api.method.FuncN;
import com.midea.base.core.serviceloader.api.service.IFactory;
import com.midea.base.core.serviceloader.api.service.ServiceLoader;
import java.util.List;
/**
* - utils:通用工具类<br/>
* - components: 辅助组件<br/>
* - service: ServiceLoader模块<br/>
* - method:方法通用接口<br/>
*/
public class ServiceLoaderHelper {
/**
* 此初始化方法必须在主线程调用。
*/
public static void init() {
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应该在主线程调用");
}
}
/**
* 此初始化方法的调用不是必须的。
* 使用时会按需初始化;但也可以提前调用并初始化,使用时会等待初始化完成。
* 本方法线程安全。
*/
public static void lazyInit() {
ServiceLoader.lazyInit();
}
/**
* 根据接口获取 {@link ServiceLoader}
*/
public static <T> ServiceLoader<T> loadService(Class<T> clazz) {
return ServiceLoader.load(clazz);
}
/**
* 创建 指定的clazz的默认实现类的实例,如果没有任何一个实现类指定了{@link IServiceLoader#defaultImpl()},
* 则会判断 指定的clazz的实现类是否只有一个,如果只有一个则会使用该实现类构造
* 如果发现有多个 指定的clazz的实现类,则会抛出异常
*
* @return 找不到或获取、构造失败,则返回null
*/
public static <I, T extends I> I getService(Class<I> clazz) {
final I service = ServiceLoader.load(clazz).get(ServiceImpl.DEFAULT_IMPL_KEY);
if (service != null) {
return service;
} else {
final List<I> services = getAllServices(clazz);
if (services.size() == 1) {
return services.get(0);
} else if (services.size() > 1) {
Debugger.fatal(DefaultServiceException.foundMoreThanOneImpl(clazz));
}
}
return null;
}
/**
* 创建 指定的clazz的默认实现类的实例,使用context参数构造,如果没有任何一个实现类指定了{@link IServiceLoader#defaultImpl()},
* 则会判断 指定的clazz的实现类是否只有一个,如果只有一个则会使用该实现类构造
* 如果发现有多个 指定的clazz的实现类,则会抛出异常
*
* @return 找不到或获取、构造失败,则返回null
*/
public static <I, T extends I> I getService(Class<I> clazz, Context context) {
final I service = ServiceLoader.load(clazz).get(ServiceImpl.DEFAULT_IMPL_KEY, context);
if (service != null) {
return service;
} else {
final List<I> services = getAllServices(clazz, context);
if (services.size() == 1) {
return services.get(0);
} else if (services.size() > 1) {
Debugger.fatal(DefaultServiceException.foundMoreThanOneImpl(clazz));
}
}
return null;
}
/**
* 创建 指定的clazz的默认实现类的实例,使用指定的Factory构造,如果没有任何一个实现类指定了{@link IServiceLoader#defaultImpl()},
* 则会判断 指定的clazz的实现类是否只有一个,如果只有一个则会使用该实现类构造
* 如果发现有多个 指定的clazz的实现类,则会抛出异常
*
* @return 找不到或获取、构造失败,则返回null
*/
public static <I, T extends I> I getService(Class<I> clazz, IFactory factory) {
final I service = ServiceLoader.load(clazz).get(ServiceImpl.DEFAULT_IMPL_KEY, factory);
if (service != null) {
return service;
} else {
final List<I> services = getAllServices(clazz, factory);
if (services.size() == 1) {
return services.get(0);
} else if (services.size() > 1) {
Debugger.fatal(DefaultServiceException.foundMoreThanOneImpl(clazz));
}
}
return null;
}
/**
* 创建指定key的实现类实例,使用 {@link IServiceProvider} 方法或无参数构造。对于声明了singleton的实现类,不会重复创建实例。
*
* @return 找不到或获取、构造失败,则返回null
*/
public static <I, T extends I> T getService(Class<I> clazz, String key) {
return ServiceLoader.load(clazz).get(key);
}
/**
* 创建指定key的实现类实例,使用Context参数构造。对于声明了singleton的实现类,不会重复创建实例。
*
* @return 找不到或获取、构造失败,则返回null
*/
public static <I, T extends I> T getService(Class<I> clazz, String key, Context context) {
return ServiceLoader.load(clazz).get(key, context);
}
/**
* 创建指定key的实现类实例,使用指定的Factory构造。对于声明了singleton的实现类,不会重复创建实例。
*
* @param factory 用于从Class构造实例
* @return 找不到或获取、构造失败,则返回null
*/
public static <I, T extends I> T getService(Class<I> clazz, String key, IFactory factory) {
return ServiceLoader.load(clazz).get(key, factory);
}
/**
* 创建所有实现类的实例,使用 {@link IServiceProvider} 方法或无参数构造。对于声明了singleton的实现类,不会重复创建实例。
*
* @return 可能返回EmptyList,List中的元素不为空
*/
public static <I, T extends I> List<T> getAllServices(Class<I> clazz) {
return ServiceLoader.load(clazz).getAll();
}
/**
* 创建所有实现类的实例,使用Context参数构造。对于声明了singleton的实现类,不会重复创建实例。
*
* @return 可能返回EmptyList,List中的元素不为空
*/
public static <I, T extends I> List<T> getAllServices(Class<I> clazz, Context context) {
return ServiceLoader.load(clazz).getAll(context);
}
/**
* 创建所有实现类的实例,使用指定Factory构造。对于声明了singleton的实现类,不会重复创建实例。
*
* @return 可能返回EmptyList,List中的元素不为空
*/
public static <I, T extends I> List<T> getAllServices(Class<I> clazz, IFactory factory) {
return ServiceLoader.load(clazz).getAll(factory);
}
/**
* 根据key获取实现类的Class。注意,对于声明了singleton的实现类,获取Class后还是可以创建新的实例。
*
* @return 找不到或获取失败,则返回null
*/
public static <I, T extends I> Class<T> getServiceClass(Class<I> clazz, String key) {
return ServiceLoader.load(clazz).getClass(key);
}
/**
* 获取所有实现类的Class。注意,对于声明了singleton的实现类,获取Class后还是可以创建新的实例。
*
* @return 可能返回EmptyList,List中的元素不为空
*/
public static <I, T extends I> List<Class<T>> getAllServiceClasses(Class<I> clazz) {
return ServiceLoader.load(clazz).getAllClasses();
}
/**
* 调用方法。方法应该实现 {@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]);
case 3:
return (T) getService(Func3.class, key).call(args[0], args[1], args[2]);
case 4:
return (T) getService(Func4.class, key).call(
args[0], args[1], args[2], args[3]);
case 5:
return (T) getService(Func5.class, key).call(
args[0], args[1], args[2], args[3], args[4]);
case 6:
return (T) getService(Func6.class, key).call(
args[0], args[1], args[2], args[3], args[4], args[5]);
case 7:
return (T) getService(Func7.class, key).call(
args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
case 8:
return (T) getService(Func8.class, key).call(
args[0], args[1], args[2], args[3],
args[4], args[5], args[6], args[7]);
case 9:
return (T) getService(Func9.class, key).call(
args[0], args[1], args[2], args[3],
args[4], args[5], args[6], args[7], args[8]);
default:
return (T) getService(FuncN.class, key).call(args);
}
}
}