1.首先我们知道要进行依赖注入的话,得先添加一个注解比如
@Autowired
String name;
@Autowired
int age;
2.然后我们在看看这个注解的定义:
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.CLASS)
public @interface Autowired {
// Mark param's name or service name.
String name() default "";
// If required, app will be crash when value is null.
// Primitive type wont be check!
boolean required() default false;
// Description of the field
String desc() default "No desc.";
}
在这里 有两个属性值得我们关注 就是name和required (第三个是 description的,已经废弃了)
name属性就是给它一个别名 比如
@Autowired(name = "boy")
boolean girl;
在传值的时候就可以用别名来传递了
required属性表示进行null判断,如果是iProvider的子类 且 为null 则抛出异常,如果不是iProvider的子类 为null的话 只是打印一句话。
首先:
@AutoService(Processor.class)
@SupportedOptions(KEY_MODULE_NAME)
@SupportedSourceVersion(SourceVersion.RELEASE_7)
@SupportedAnnotationTypes({ANNOTATION_TYPE_AUTOWIRED})
public class AutowiredProcessor extends AbstractProcessor {
private Filer mFiler; // File util, write class file into disk.
private Logger logger;
private Types types;
private TypeUtils typeUtils;
private Elements elements;
private Map> parentAndChild = new HashMap<>(); // Contain field need autowired and his super class.
private static final ClassName ARouterClass = ClassName.get("com.alibaba.android.arouter.launcher", "ARouter");
private static final ClassName AndroidLog = ClassName.get("android.util", "Log");
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
mFiler = processingEnv.getFiler(); // Generate class.
types = processingEnv.getTypeUtils(); // Get type utils.
elements = processingEnv.getElementUtils(); // Get class meta.
typeUtils = new TypeUtils(types, elements);
logger = new Logger(processingEnv.getMessager()); // Package the log utils.
logger.info(">>> AutowiredProcessor init. <<<");
}
}
这一段代码中,我们最需要知道的一点就是parentAndChild,这个容器装了当前类中所有的需要依赖注入的字段(这段就比较水了,哈哈哈)。
接下来看到这段代码:
@Override
public boolean process(Set extends TypeElement> set, RoundEnvironment roundEnvironment) {
if (CollectionUtils.isNotEmpty(set)) {
try {
logger.info(">>> Found autowired field, start... <<<");
categories(roundEnvironment.getElementsAnnotatedWith(Autowired.class));
generateHelper();
} catch (Exception e) {
logger.error(e);
}
return true;
}
return false;
}
这段代码中会调用2个方法
categories(roundEnvironment.getElementsAnnotatedWith(Autowired.class));
generateHelper();
private void categories(Set extends Element> elements) throws IllegalAccessException {
if (CollectionUtils.isNotEmpty(elements)) {
for (Element element : elements) {
TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
if (element.getModifiers().contains(Modifier.PRIVATE)) {
throw new IllegalAccessException("The autowired fields CAN NOT BE 'private'!!! please check field ["
+ element.getSimpleName() + "] in class [" + enclosingElement.getQualifiedName() + "]");
}
if (parentAndChild.containsKey(enclosingElement)) { // Has categries
parentAndChild.get(enclosingElement).add(element);
} else {
List childs = new ArrayList<>();
childs.add(element);
parentAndChild.put(enclosingElement, childs);
}
}
logger.info("categories finished.");
}
}
第一步(获取下标为0的element的TypeElement):
TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
第二步(判断当前字段的可见性,如果是private,就抛出错误)
if (element.getModifiers().contains(Modifier.PRIVATE)) {
throw new IllegalAccessException("The autowired fields CAN NOT BE 'private'!!! please check field ["
+ element.getSimpleName() + "] in class [" + enclosingElement.getQualifiedName() + "]");
}
第三步(先看容器里面是否有当前class的key,如果没有就添加进去,如果有,则直接把value加入其中,这一步貌似不需要讲解,不过凑凑字数):
if (parentAndChild.containsKey(enclosingElement)) { // Has categries
parentAndChild.get(enclosingElement).add(element);
} else {
List childs = new ArrayList<>();
childs.add(element);
parentAndChild.put(enclosingElement, childs);
}
这个方法的代码有点长,还是一段一段的看
第一段:
TypeElement type_ISyringe = elements.getTypeElement(ISYRINGE);
TypeElement type_JsonService = elements.getTypeElement(JSON_SERVICE);
TypeMirror iProvider = elements.getTypeElement(Consts.IPROVIDER).asType();
TypeMirror activityTm = elements.getTypeElement(Consts.ACTIVITY).asType();
TypeMirror fragmentTm = elements.getTypeElement(Consts.FRAGMENT).asType();
TypeMirror fragmentTmV4 = elements.getTypeElement(Consts.FRAGMENT_V4).asType();
// Build input param name.
ParameterSpec objectParamSpec = ParameterSpec.builder(TypeName.OBJECT, "target").build();
这一段就没什么好说的了 TypeElement , TypeMirror 都是一些在apt中使用的类,平时不太能用到,笔者也就知道这些东西,到底怎么用呢,也不是特别清楚,只能说是需要用到的时候在查吧,其他他们都是对类的一些描述。 ParameterSpec 这个是一个第三方库(javapoet)的对象,这个库可以用来生成java文件,解放你的双手,关于这个库的使用,大家可以去百度一下,或者 传送门
第二段:
if (MapUtils.isNotEmpty(parentAndChild)) {
for (Map.Entry> entry : parentAndChild.entrySet()) {
//生成inject方法(都是javapoet的语法)
MethodSpec.Builder injectMethodBuilder = MethodSpec.methodBuilder(METHOD_INJECT)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(objectParamSpec);
//获取到当前注解的类名
TypeElement parent = entry.getKey();
//获取这个类中需要依赖注入的字段
List childs = entry.getValue();
String qualifiedName = parent.getQualifiedName().toString();
String packageName = qualifiedName.substring(0, qualifiedName.lastIndexOf("."));
String fileName = parent.getSimpleName() + NAME_OF_AUTOWIRED;
logger.info(">>> Start process " + childs.size() + " field in " + parent.getSimpleName() + " ... <<<");
//这里是生成public class xxx implements ISyringe
TypeSpec.Builder helper = TypeSpec.classBuilder(fileName)
.addJavadoc(WARNING_TIPS)
.addSuperinterface(ClassName.get(type_ISyringe))
.addModifiers(PUBLIC);
//这里是生成了一个成员对象 SerializationService
FieldSpec jsonServiceField = FieldSpec.builder(TypeName.get(type_JsonService.asType()), "serializationService", Modifier.PRIVATE).build();
//将这个成员对象加入的当前文件中
helper.addField(jsonServiceField);
//这段是在inject方法中加入下面这段代码
//serializationService =ARouter.getInstance().navigation(SerializationService.class);;
injectMethodBuilder.addStatement("serializationService = $T.getInstance().navigation($T.class);", ARouterClass, ClassName.get(type_JsonService));
injectMethodBuilder.addStatement("$T substitute = ($T)target", ClassName.get(parent), ClassName.get(parent));
第三段:
// Generate method body, start inject.
//遍历每一个需要依赖注入的对象
for (Element element : childs) {
Autowired fieldConfig = element.getAnnotation(Autowired.class);
//获取到当前需要注入对象的字段名
String fieldName = element.getSimpleName().toString();
//如果是iProvider的子类
if (types.isSubtype(element.asType(), iProvider)) { // It's provider
//没有设置name,则通过byType的方式
if ("".equals(fieldConfig.name())) { // User has not set service path, then use byType.
// Getter
//这段代码生成substitute.xxx = ARouter.getInstance().navigation(xxx.class);
injectMethodBuilder.addStatement(
"substitute." + fieldName + " = $T.getInstance().navigation($T.class)",
ARouterClass,
ClassName.get(element.asType())
);
} else { // use byName
// Getter
//这段代码生成了substitute.xxx= ARouter.getInstance()build("yyy").navigation();
injectMethodBuilder.addStatement(
"substitute." + fieldName + " = ($T)$T.getInstance().build($S).navigation();",
ClassName.get(element.asType()),
ARouterClass,
fieldConfig.name()
);
}
// Validater
//这里就是文章最前面讲到的required字段,如果为null则crash
if (fieldConfig.required()) {
injectMethodBuilder.beginControlFlow("if (substitute." + fieldName + " == null)");
injectMethodBuilder.addStatement(
"throw new RuntimeException(\"The field '" + fieldName + "' is null, in class '\" + $T.class.getName() + \"!\")", ClassName.get(parent));
injectMethodBuilder.endControlFlow();
}
} else { // It's normal intent value
//非iProvider的子类
String statment = "substitute." + fieldName + " = substitute.";
boolean isActivity = false;
if (types.isSubtype(parent.asType(), activityTm)) { // Activity, then use getIntent()
//如果是activity的子类
isActivity = true;
statment += "getIntent().";
} else if (types.isSubtype(parent.asType(), fragmentTm) || types.isSubtype(parent.asType(), fragmentTmV4)) { // Fragment, then use getArguments()
//如果是fragment的子类
statment += "getArguments().";
} else {
throw new IllegalAccessException("The field [" + fieldName + "] need autowired from intent, its parent must be activity or fragment!");
}
//buildStatement方法 稍后再讲
statment = buildStatement(statment, typeUtils.typeExchange(element), isActivity);
if (statment.startsWith("serializationService.")) { // Not mortals
injectMethodBuilder.beginControlFlow("if (null != serializationService)");
//如果没有设置name则直接用字段名字,如果设置了name则用name的名字
injectMethodBuilder.addStatement(
"substitute." + fieldName + " = " + statment,
(StringUtils.isEmpty(fieldConfig.name()) ? fieldName : fieldConfig.name()),
ClassName.get(element.asType())
);
injectMethodBuilder.nextControlFlow("else");
injectMethodBuilder.addStatement(
"$T.e(\"" + Consts.TAG + "\", \"You want automatic inject the field '" + fieldName + "' in class '$T' , then you should implement 'SerializationService' to support object auto inject!\")", AndroidLog, ClassName.get(parent));
injectMethodBuilder.endControlFlow();
} else {
injectMethodBuilder.addStatement(statment, StringUtils.isEmpty(fieldConfig.name()) ? fieldName : fieldConfig.name());
}
// Validator
if (fieldConfig.required() && !element.asType().getKind().isPrimitive()) { // Primitive wont be check.
injectMethodBuilder.beginControlFlow("if (null == substitute." + fieldName + ")");
injectMethodBuilder.addStatement(
"$T.e(\"" + Consts.TAG + "\", \"The field '" + fieldName + "' is null, in class '\" + $T.class.getName() + \"!\")", AndroidLog, ClassName.get(parent));
injectMethodBuilder.endControlFlow();
}
}
}
helper.addMethod(injectMethodBuilder.build());
// Generate autowire helper
// 生成文件
JavaFile.builder(packageName, helper.build()).build().writeTo(mFiler);
logger.info(">>> " + parent.getSimpleName() + " has been processed, " + fileName + " has been generated. <<<");
}
logger.info(">>> Autowired processor stop. <<<");
}
private String buildStatement(String statment, int type, boolean isActivity) {
if (type == TypeKind.BOOLEAN.ordinal()) {
statment += (isActivity ? ("getBooleanExtra($S, false)") : ("getBoolean($S)"));
} else if (type == TypeKind.BYTE.ordinal()) {
statment += (isActivity ? ("getByteExtra($S, (byte) 0)") : ("getByte($S)"));
} else if (type == TypeKind.SHORT.ordinal()) {
statment += (isActivity ? ("getShortExtra($S, (short) 0)") : ("getShort($S)"));
} else if (type == TypeKind.INT.ordinal()) {
statment += (isActivity ? ("getIntExtra($S, 0)") : ("getInt($S)"));
} else if (type == TypeKind.LONG.ordinal()) {
statment += (isActivity ? ("getLongExtra($S, 0)") : ("getLong($S)"));
} else if (type == TypeKind.FLOAT.ordinal()) {
statment += (isActivity ? ("getFloatExtra($S, 0)") : ("getFloat($S)"));
} else if (type == TypeKind.DOUBLE.ordinal()) {
statment += (isActivity ? ("getDoubleExtra($S, 0)") : ("getDouble($S)"));
} else if (type == TypeKind.STRING.ordinal()) {
statment += (isActivity ? ("getStringExtra($S)") : ("getString($S)"));
} else if (type == TypeKind.PARCELABLE.ordinal()) {
statment += (isActivity ? ("getParcelableExtra($S)") : ("getParcelable($S)"));
} else if (type == TypeKind.OBJECT.ordinal()) {
statment = "serializationService.json2Object(substitute." + (isActivity ? "getIntent()." : "getArguments().") + (isActivity ? "getStringExtra($S)" : "getString($S)") + ", $T.class)";
}
return statment;
}
这个方法就是根据需要注入的字段的类型,去拼接相应的代码。
首先 我们需要在onCreate()中写一段代码
ARouter.getInstance().inject(this);
继续跟进代码
public void inject(Object thiz) {
_ARouter.inject(thiz);
}
再次进入
static void inject(Object thiz) {
AutowiredService autowiredService = ((AutowiredService) ARouter.getInstance().build("/arouter/service/autowired").navigation());
if (null != autowiredService) {
autowiredService.autowire(thiz);
}
}
发现这是_ARouter的一个静态代码块。就是一开始就会被加载进内存中,然后我们在进入autowire()方法
@Override
public void autowire(Object instance) {
String className = instance.getClass().getName();
try {
if (!blackList.contains(className)) {
ISyringe autowiredHelper = classCache.get(className);
if (null == autowiredHelper) { // No cache.
autowiredHelper = (ISyringe) Class.forName(instance.getClass().getName() + SUFFIX_AUTOWIRED).getConstructor().newInstance();
}
autowiredHelper.inject(instance);
classCache.put(className, autowiredHelper);
}
} catch (Exception ex) {
blackList.add(className); // This instance need not autowired.
}
}
看到这里 大家就明白了吧,首先通过传入的对象,拿到对象的类名,然后通过这个类名去构造一个之前apt生成的与这个类相关的Autowired对象,比如 Test1Activity 中有字段需要依赖注入,那么这里就是构造一个Test1Activity$$ARouter$$Autowired 的对象,然后调用inject() 方法,将当前对象传递进去,这样就完成了我们的依赖注入了。
我们可以看看 apt生成的类
public class Test1Activity$$ARouter$$Autowired implements ISyringe {
private SerializationService serializationService;
@Override
public void inject(Object target) {
serializationService = ARouter.getInstance().navigation(SerializationService.class);;
Test1Activity substitute = (Test1Activity)target;
substitute.name = substitute.getIntent().getStringExtra("name");
substitute.age = substitute.getIntent().getIntExtra("age", 0);
substitute.girl = substitute.getIntent().getBooleanExtra("boy", false);
substitute.pac = substitute.getIntent().getParcelableExtra("pac");
if (null == substitute.pac) {
Log.e("ARouter::", "The field 'pac' is null, in class '" + Test1Activity.class.getName() + "!");
}
if (null != serializationService) {
substitute.obj = serializationService.json2Object(substitute.getIntent().getStringExtra("obj"), TestObj.class);
} else {
Log.e("ARouter::", "You want automatic inject the field 'obj' in class 'Test1Activity' , then you should implement 'SerializationService' to support object auto inject!");
}
substitute.url = substitute.getIntent().getStringExtra("url");
substitute.helloService = ARouter.getInstance().navigation(HelloService.class);
}
}