Detailed explanation of spring annotation programming model
In spring, there is a concept called meta annotation, which realizes the "derivation" of annotations through meta annotation. The official term is "annotation hierarchy".
What is meta annotation
The so-called meta annotation is the annotation marked on the annotation. In the annotation hierarchy formed in this way, the meta annotation is above the hierarchy, which I call super annotation, and the annotated annotation is below the hierarchy, which is called sub annotation. The purpose of introducing meta annotation is to achieve attribute override.
Take a simple example:
There is a class home and two annotations. One is called @ parent, the other is called @ child, @ parent is marked on @ child, and @ child is marked on home. They all have only one attribute, name, if @ parent The default value of name is' John ', while @ child The default value of name is' Jack '.
At this time, get @ child. Com from home Name, you should return 'Jack', which is no suspense.
Then, if you get @ parent Name, what should be returned? According to the "derivation" of spring annotation, @ child name override @Parent. Name, so the returned result is also 'Jack'.
For the classes and annotations in the above example, the code is roughly as follows
@interface Parent { String name() default "John"; } @Parent @interface Child { String name() default "Jack"; } @Child class Home { }
Annotation hierarchy:
@Parent
@Child
Compared with "attribute rewriting", another concept is "attribute alias". Attribute aliases are equivalent to each other.
We add an attribute value to @ child above, and use @ aliasfor to make @ child Name and @ child Value becomes an alias for each other, and the default value is an empty string:
@interface Child { @AliasFor("name") String value() default ""; @AliasFor("value") String name() default ""; }
When marked on home, give @ child Value is set to "Jack":
@Child("Jack") class Home { }
At this time, whether you get @ child Name still gets @ child Value, the result is always the same, all of which are "Jack". It illustrates the equivalence between attribute aliases.
Property aliases and property overrides
Attribute alias and attribute rewriting are actually two completely different concepts, but if they are not distinguished and fuzzy, they will be surprised that some phenomena do not meet expectations. Consider the following cases and give the values of @ a.a1, @ a.a2, @ b.a1, @ B.B, @ C.C, @ C.B respectively:
@interface A { String a1() default "1"; String a2() default "1"; } @A @interface B { String a1() default "2"; @AliasFor(value = "a2",annotation = A.class) String b() default "2"; } @B @interface C { @AliasFor(value = "a1",annotation = B.class) String c() default "3"; String b() default "3"; }
Before I understand the concept, I think the answer should be: @ a.a1, @ a.a2, @ b.a1, @ B.B, @ C.C, @ C.B are all "3". The reasons are as follows.
As a result, I was wrong. The values of @ b.a1, @ B.B, @ C.C and @ C.B were "3", but the values of @ a.a1 and @ a.a2 were "2".
As for why, let's carefully understand the two concepts of attribute alias and attribute rewriting.
Citing official wikis https://github.com/spring-projects/spring-framework/wiki/Spring-Annotation-Programming-Model , there are clarifications on these two concepts. In the section "attribute aliases and overrides", the official text is as follows:
There are three kinds of attribute aliases: explicit alias, implicit alias and pass through implicit alias. Attribute alias can only occur within the same annotation. For example:
Explicit aliases (mutual @ aliasfor), @ a.a1 and @ a.a2,
@interface A { @AliasFor("a2") String a1() default ""; @AliasFor("a1") String a2() default ""; }
Implicit aliases (@ aliasfor to the same attribute), @ b.b1 and @ b.b2
@interface A { String a() default ""; } @A @interface B { @AliasFor(value = "a",annotation = A.class) String b1() default ""; @AliasFor(value = "a",annotation = A.class) String b2() default ""; }
Pass implicit aliases (eventually @ aliasfor to the same attribute) @ c.c1 and @ c.c2
@interface A { String a() default ""; } @A @interface B { @AliasFor(value = "a",annotation = A.class) String b() default ""; } @B @interface C { @AliasFor(value = "a",annotation = A.class) String c1() default ""; @AliasFor(value = "b",annotation = B.class) String c2() default ""; }
There are also three types of attribute Rewriting: implicit rewriting, explicit rewriting and transitive explicit rewriting. Attribute rewriting can only occur between annotations. For example:
Implicit override (property with the same name), @ B.A overrides @ A.A
@interface A { String a() default ""; } @A @interface B { String a() default ""; }
Explicit override (requires @ aliasfor), @ B.B overrides @ A.A
@interface A { String a() default ""; } @A @interface B { @AliasFor(value = "a",annotation = A.class) String b() default ""; }
Pass explicit override (requires @ aliasfor). Since @ C.C overrides @ B.B and @ B.B overrides @ A.A, @ C.C also overrides @ A.A
@interface A { String a() default ""; } @A @interface B { @AliasFor(value = "a",annotation = A.class) String b() default ""; } @B @interface C { @AliasFor(value = "b",annotation = B.class) String c() default ""; }
After understanding clearly, let's go back to the topic just now. The example is pasted as follows:
@interface A { String a1() default "1"; String a2() default "1"; } @A @interface B { String a1() default "2"; @AliasFor(value = "a2",annotation = B.class) String c() default "3"; String b() default "3"; }
The answer steps are:
You can see that there is no relationship between @ A and @ C. There is no "attribute alias" here. Either @ aliasfor or "attribute alias" is used.
For "explicit transfer rewriting", such as "@ a.a1 is implicitly rewritten by @ b.a1, @ b.a1 is explicitly rewritten by @ C.C", or "@ a.a2 is explicitly rewritten by @ B.B, and B.B is implicitly rewritten by @ C.B", the rewriting relationship will not be transferred.
summary
There are three kinds of attribute aliases: explicit alias, implicit alias and pass through implicit alias. Attribute alias can only occur within the same annotation. There are also three types of attribute Rewriting: implicit rewriting, explicit rewriting and transitive explicit rewriting. Attribute rewriting can only occur between annotations.
Postscript
Spring's code implementation of the annotation programming model is mainly in the annotatedelementutils class. This method can be used for experiments:
AnnotatedElementUtils#getMergedAnnotationAttributes。
It should be noted that "implicit override" does not apply to the value attribute. It seems that the value attribute is a relatively special attribute.
In the following example, @ b.value does not implicitly override @ a.value
@interface A { String value() default "a"; } @A @interface B { String value() default "b"; }
However, as long as the attribute name is not value, it can be implicitly rewritten, @ b.xxx implicitly rewrites @ A.xxx
@interface A { String xxx() default "a"; } @A @interface B { String xxx() default "b"; }
I followed the following source code and found that the source code did make a special judgment on the value attribute. The code is located at org springframework. core. annotation. AnnotatedElementUtils. In the mergedannotationattributesprocessor #postprocess method, the code snippet is as follows:;
// Implicit annotation attribute override based on convention else if (!AnnotationUtils.VALUE.equals(attributeName) && attributes.containsKey(attributeName)) { overrideAttribute(element,annotation,attributes,attributeName,attributeName); }
Where annotationutils Value is a constant with a value of "value". There is no official explanation for why the value attribute should be specially treated. The guess is that many annotations have only one attribute. For programming convenience, you don't need @ a (value = "Hello world") to use it, just @ a ("Hello world"). In this case, if you implicitly rewrite it, it may not be the result that the coder wants.
It is worth mentioning that explicit rewriting does not have such special processing. The following example @ b.value will explicitly rewrite @ a.value:
@interface A { String value() default "a"; } @A @interface B { @AliasFor(annotation = A.class) String value() default "b"; }
This article discusses the spring boot version > = 2.0 2.RELEASE。
The above is the whole content of this article. I hope it will help you in your study, and I hope you will support us a lot.