-
1 – InterceptorProcessor ARouter to explain
-
2 – AutowiredProcessor ARouter interpretation
-
3 _routeprocessor ARouter interpretation
-
4 _core Arouter explanation
An overview of the
Note that AbstractProcessor handles annotations in a way that AbstractProcessor does not. This article introduces Arouter’s annotations at the source level.
InterceptorProcessor annotations
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.CLASS)
public @interface Interceptor {
/** * Weight value, the smaller the weight is */
int priority(a);
/** * The name of interceptor, may be used to generate javadoc. */
String name(a) default "Default";
}
Copy the code
When using path for routing, you can intercept it, for example by intercepting additional parameters.
Functions overview
The main logic is to find all the classes that are Interceptor annotated, generate a class like the one below, and wait until Arouter initializes to call loadInto, So that puts the value into the Map<Integer that we specify, Class<? Extends IInterceptor>> in. When interceptors are invoked will be covered in the next few articles.
public class ARouter$$Interceptors$$modulejava implements IInterceptorGroup {
@Override
public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) {
interceptors.put(7, Test1Interceptor.class);
interceptors.put(90, TestInterceptor90.class); }}Copy the code
Functional details
@AutoService(Processor.class)
Copy the code
This is Google’s auto – service – the annotation, mainly is to help us generate meta-inf/services/javax.mail annotation. Processing. The Processor files, otherwise it will be manually write it himself.
@SupportedAnnotationTypes(ANNOTATION_TYPE_INTECEPTOR)
Copy the code
ANNOTATION_TYPE_INTECEPTOR value is com. Alibaba. Android. Arouter. The facade. The annotation. The Interceptor, said the types of annotation to deal with
The old way of writing it was like this
@Override
public Set<String> getSupportedAnnotationTypes(a) {
return super.getSupportedAnnotationTypes();
}
Copy the code
SupportedAnnotationTypes annotations are SupportedAnnotationTypes annotations can be used after 1.6.
public Set<String> getSupportedAnnotationTypes(a) {
SupportedAnnotationTypes sat = this.getClass().getAnnotation(SupportedAnnotationTypes.class);
if (sat == null) {
if (isInitialized())
processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING,
"No SupportedAnnotationTypes annotation " +
"found on " + this.getClass().getName() +
", returning an empty set.");
return Collections.emptySet();
}
else
return arrayToSet(sat.value());
}
Copy the code
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
/ / get be com. Alibaba. Android. Arouter. The facade. The template. IInterceptor
iInterceptor = elementUtils.getTypeElement(Consts.IINTERCEPTOR).asType();
}
Copy the code
The key method is the following process In Java, there are PACKAGE, ENUM, CLASS, ANNOTATION_TYPE, INTERFACE, FIELD, method or PARAMETER that constructs functions LOCAL_VARIABLE, METHOD, CONSTRUCTOR, etc.
These make up Java programs, each of which is called an Element.
- Set getModifiers() get the Element’s modifiers (public, static, etc.)
- ElementKind getKind() gets what kind of Element it is.
- Name getSimpleName() gets the Name of the Element
- Element getEnclosingElement() returns PackageElement if Element is a top-level class or interface (TypeElement), or null if it is a PackageElement
- List
getEnclosedElements() returns other elements wrapped around that Element. For example, a class can contain constructor Element, field Element, method Element, and so on. - A getAnnotation(ClassAnnotationType) gets the annotation specified on the Element.
- TypeMirror asType()
From Element you can get what structure of the Java language Element is currently. For example, an int age can be a FIELD or a method PARAMETER, but how do you know what type it is? String, int, or long, and then you can use asType, which becomes TypeMirror, and by using getKind() you know that age is an int.
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (CollectionUtils.isNotEmpty(annotations)) {
// Get the element annotated by the Interceptor first
Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(Interceptor.class);
try {
parseInterceptors(elements);
} catch (Exception e) {
logger.error(e);
}
return true; // Return true to indicate that this is handled by me and will not be handled by subsequent annotators
}
return false;
}
Copy the code
private void parseInterceptors(Set<? extends Element> elements) throws IOException {
if (CollectionUtils.isNotEmpty(elements)) {
// Verify and cache, sort incidentally.
// Loop through each element that is Interceptor annotated
for (Element element : elements) {
/ / check, element must be Interceptor annotations, and must be directly implement com. Alibaba. Android. Arouter. The facade. The annotation. The Interceptor interface
// The thing to note here is the direct implementation
if (verify(element)) { // Check the interceptor meta
// Get the value of the Interceptor annotation
Interceptor interceptor = element.getAnnotation(Interceptor.class);
// We can't have two interceptors with equal weight
Element lastInterceptor = interceptors.get(interceptor.priority());
if (null! = lastInterceptor) {// Added, throw exceptions
throw new IllegalArgumentException(
String.format(Locale.getDefault(), "More than one interceptors use same priority [%d], They are [%s] and [%s].",
interceptor.priority(),
lastInterceptor.getSimpleName(),
element.getSimpleName())
);
}
/ / save it
interceptors.put(interceptor.priority(), element);
} else {
logger.error("A interceptor verify failed, its "+ element.asType()); }}// Interface of ARouter.
// com.alibaba.android.arouter.facade.template.IInterceptor
TypeElement type_ITollgate = elementUtils.getTypeElement(IINTERCEPTOR);
// com.alibaba.android.arouter.facade.template.IInterceptorGroup
TypeElement type_ITollgateGroup = elementUtils.getTypeElement(IINTERCEPTOR_GROUP);
/** * generates an input type, followed by the method parameters ** Map
>``` */
,>
ParameterizedTypeName inputMapTypeOfTollgate = ParameterizedTypeName.get(
ClassName.get(Map.class),
ClassName.get(Integer.class),
ParameterizedTypeName.get(
ClassName.get(Class.class),
WildcardTypeName.subtypeOf(ClassName.get(type_ITollgate))
)
);
// Enter the name of the parameter
ParameterSpec tollgateParamSpec = ParameterSpec.builder(inputMapTypeOfTollgate, "interceptors").build();
// Generate the method name loadInto
MethodSpec.Builder loadIntoMethodOfTollgateBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(tollgateParamSpec);
// Generate
if (null! = interceptors && interceptors.size() >0) {
// Build method body
for (Map.Entry<Integer, Element> entry : interceptors.entrySet()) {
loadIntoMethodOfTollgateBuilder.addStatement("interceptors.put(" + entry.getKey() + ", $T.class)", ClassName.get((TypeElement) entry.getValue())); }}// Write to disk(Write file even interceptors is empty.)
ModuleName = moduleName. ReplaceAll ("[^ 0-9a-za-z_]+", ""); moduleName = moduleName. Is modulejava
/ / package name com. Alibaba. Android. Arouter. Routes
/ / the name of the class ARouter $$$$modulejava Interceptors
JavaFile.builder(PACKAGE_OF_GENERATE_FILE,
TypeSpec.classBuilder(NAME_OF_INTERCEPTOR + SEPARATOR + moduleName)
.addModifiers(PUBLIC)
.addJavadoc(WARNING_TIPS)
.addMethod(loadIntoMethodOfTollgateBuilder.build())
.addSuperinterface(ClassName.get(type_ITollgateGroup))
.build()
).build().writeTo(mFiler);
logger.info(">>> Interceptor group write over. <<<"); }}Copy the code
Through the annotation handler, the content of the generated file is
/** * DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class ARouter$$Interceptors$$modulejava implements IInterceptorGroup {
@Override
public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) {
interceptors.put(7, Test1Interceptor.class);
interceptors.put(90, TestInterceptor90.class); }}Copy the code