注解组件化方案:https://github.com/luiing/Assignor
目前市面上的组件化方案原理:scheme,代码注入Aop,代码生成等;
本方案利用注解处理器生成代码,优点是简单便捷,集成方便;
原理:注解Test.class为abc,在注解处理器运行时生成一个java源文件abcGenerate.java,里面包含了被注解类的无参对象Object abc=new Test(),在调用abc组件时,通过反射方法取到生成的变量abc,剩下的就是调用该类的方法。
1. 创建注解类
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface BindCall {
String value() default "";
}
2. 注解处理器实现,注解处理器在编译前运行
增加文件:resources/META-INF/services/javax.annotation.processing.Processor
内容为注解处理器全包名:com.uis.call.BindCallProcessor
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes({"com.uis.call.BindCall"})
public class BindCallProcessor extends AbstractProcessor {
Filer filer;
Messager messager;
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
filer = processingEnvironment.getFiler();
messager = processingEnvironment.getMessager();
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
for (Element element : roundEnvironment.getElementsAnnotatedWith(BindCall.class)) {
if(element.getKind() == ElementKind.CLASS) {
String clsName = element.getAnnotation(BindCall.class).value();
System.out.println("---CallProcessor name="+element.getSimpleName()+",value="+clsName);
if(clsName.isEmpty() || !clsName.matches("[a-zA-Z_]\\w*")){
System.out.println("---CallProcessor generate fail:"+clsName+" is not java class name");
}else{
createJavaFile(clsName,element);
}
}
}
return false;
}
private void createJavaFile(String clsName,Element element) {
try {
String pkgName = BindCallUtils.generatePkg;
String extName = clsName + BindCallUtils.generate;
JavaFileObject javaFile = filer.createSourceFile(pkgName+"."+extName);
BufferedWriter writer = new BufferedWriter(javaFile.openWriter());
writer.write("package "+pkgName+";\n\n");
writer.write("public class "+extName+"{\n\n");
writer.write(" public final Object "+clsName+" = new "+element.toString()+"();\n\n");
writer.write("}\n");
writer.flush();
writer.close();
}catch (Exception ex){
ex.printStackTrace();
}
}
}
3. 组件调用核心代码
public class BindCallUtils {
public static String generatePkg = "a.b.c.d.generate";
public static String generate = "Generate";
//找到注解处理器生成的field
public static Object getCallValue(String bindName){
String clsName = generatePkg + "." + bindName + generate;
try {
Class<?> cls = Class.forName(clsName);
Field field = cls.getField(bindName);
field.setAccessible(true);
return field.get(cls.newInstance());
}catch (Throwable ex){
System.out.println("------ Not found "+clsName+" ------");
}
return null;
}
}
public Result call(){
ICall call = getCall();
if(call != null){
return call.onCall(param);
}
return newResult(param.id).error(404,"Not found "+param.callName).build();
}
public void call(IResult result){
final ICall call = getCall();
sResult.put(param.id,result);
if(call != null){
Worker.ioExecute(new Function0<Unit>() {
@Override
public Unit invoke() {
call.onCallback(param);
return null;
}
});
}else{
newResult(param.id).error(404,"Not found "+param.callName).build();
}
}
private ICall getCall(){
ICall call = null;
if(!TextUtils.isEmpty(param.callName)) {
WeakReference<ICall> ref = sCall.get(param.callName);
if (ref != null) {
call = ref.get();
}
if (call == null) {
Object value = BindCallUtils.getCallValue(param.callName);
if (value != null) {
call = (ICall) value;
sCall.put(param.callName, new WeakReference<>(call));
}
}
}
return call;
}
4.组件实现和使用
@BindCall("Test")
public class CoupleTest extends SimpleCall {
@Override
public void onCallback(Call.Params param) {
SystemClock.sleep(2000);
Call.newResult(param.id).success().addParam("name",param.toString()).build();
}
@Override
public Call.Result onCall(Call.Params param) {
return Call.newResult(param.id).success().addParam("name",param.toString()).build();
}
}
Call.Result result = Call.newParams("Test")
.setAction("a")
.addParam("key","111")
.call();
ALog.e(result.toString());
Call.newParams("Test")
.setAction("b")
.addParam("key","222").call(new IResult() {
@Override
public void onResult(Call.Result result) {
ALog.e(result.toString());
}
});