In Spring's many annotations, it is often found that many different attributes of different annotations play the same role, such as @RequestMapping's value
attribute and path
attribute. In order to keep their behavior consistent, such as the value of value
and the value of path
can not conflict, their values should always be equal. To handle these issues uniformly, Spring created the @AliasFor tag.
The @AliasFor tag has the following usage methods.
For example, the usage in @RequestMapping:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
@AliasFor("path")
String[] value() default {};
@AliasFor("value")
String[] path() default {};
//...
}
In the future, the functions of path
and value
are the same.
Another example is the value
attribute and the locations
attribute in the @ContextConfiguration annotation:
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ContextConfiguration {
@AliasFor("locations")
String[] value() default {};
@AliasFor("value")
String[] locations() default {};
//...
}
The two attributes locations
and value
are aliased to each other, and their functions are the same.
And also you need to pay attention to:
-
Annotaions that are aliased to each other must appear in pairs
Since
locations
is an alias forvalue
,value
must also be used instead oflocations
. So the annotations must appear in pairs. -
Attributes marked by @AliasFor must have default values
Then if the definition of the alias is violated, an error will be reported during the use. Let's do a simple test:
@ContextConfiguration(value = "aa.xml", locations = "bb.xml")
public class AnnotationUtilsTest {
@Test
public void testAliasfor() {
ContextConfiguration cc = AnnotationUtils.findAnnotation(getClass(),
ContextConfiguration.class);
System.out.println(
StringUtils.arrayToCommaDelimitedString(cc.locations()));
System.out.println(StringUtils.arrayToCommaDelimitedString(cc.value()));
}
}
If you try to perform the above test, you will find that the program is reporting an error. value
and locations
are aliases of each other and cannot be set to different values.
Adjust the code slightly:
@MyAnnotation
@ContextConfiguration(value = "aa.xml", locations = "aa.xml")
public class AnnotationUtilsTest {
or
@MyAnnotation
@ContextConfiguration(value = "aa.xml")
public class AnnotationUtilsTest {
and run:
aa.xml
aa.xml
You will find that the program is now working properly.
Let's look at a piece of code:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AopConfig.class)
public class AopUtilsTest {
This code is a very familiar JavaTest-based Spring test code.
If I have a preference now, I think it's too much trouble to write @ContextConfiguration(classes = AopConfig.class)
every time. I want to write a little simpler, I can define a tag like this:
@Retention(RetentionPolicy.RUNTIME)
@ContextConfiguration
public @interface STC {
@AliasFor(value = "classes", annotation = ContextConfiguration.class)
Class<?>[] cs() default {};
}
Because the @ContextConfiguration
annotation itself is defined as @Inherited
, our STC
annotation can be understood as inheriting the @ContextConfiguration
annotation.
I think the classes
property is too long, so I created a cs
property. In order to make this property equivalent to the classes
property in the @ContextConfiguration
property, I used the @AliasFor
tag. I set value
(as an alias for which attribute) and annotation
(as an annotation).
Use our STC
:
@RunWith(SpringJUnit4ClassRunner.class)
@STC(cs = AopConfig.class)
public class AopUtilsTest {
@Autowired
private IEmployeeService service;
works fine.
This is the second usage of the @AliasFor tag, which shows the aliases for the attributes in the meta annotation. There are also some restrictions at this time, such as the default value of the attribute type must be the same. Of course, in this use case, @AliasFor can only alias the meta annotation of the current annotation.
This usage is similar to the second one. We use the Spring official documentation directly:
@ContextConfiguration
public @interface MyTestConfig {
@AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
String[] value() default {};
@AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
String[] groovyScripts() default {};
@AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
String[] xmlFiles() default {};
}
As you can see, in the MyTestConfig
annotation, the alias @AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
is defined on value
, groovyScripts
, xmlFiles
.
So, in fact, in this annotation, value
, groovyScripts
and xmlFiles
are also aliases to each other.
@AliasFor annotation is to allow the transfer between aliases, simply understand that if A is an alias of B, and B is an alias of C, then A is an alias of C;
@MyTestConfig
public @interface GroovyOrXmlTestConfig {
@AliasFor(annotation = MyTestConfig.class, attribute = "groovyScripts")
String[] groovy() default {};
@AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
String[] xml() default {};
}
1, GroovyOrXmlTestConfig
take @MyTestConfig
(refer to the previous case) as a meta-annotation;
2, defines the groovy
attribute, and as an alias for the groovyScripts
attribute in MyTestConfig
;
3, defines the xml
attribute, and as an alias for the locations
attribute in ContextConfiguration
;
4, because the groovyScripts
attribute of MyTestConfig
is itself an alias for the locations
attribute in ContextConfiguration
; so the xml
attribute and the groovy
attribute are also aliases to each other;
Read more in https://github.com/codeman-springboot/Blogs/wiki
Thank you. But I still don't know why spring needs both path and value if the function are the same?