第一种情况
可以作为别名,比如,当向注解AliasForAnnotation 的属性location赋值时,我们可以这样写AliasForAnnotation (location="/s/b"),但是能不能省掉location呢?也就是AliasForAnnotation ("/s/b"),可以
的,因为注解定义了,当属性值是value就可以,那就向AliasForAnnotation 新增一个value属性即可,但是当你AliasForAnnotation ("/s/b")时,location没有值,那如何做到既可以AliasForAnnotation ("/s/b"),location也有值呢?可以使用spring提供的 @AliasFor,但是这个注解需要结合AnnotationUtils.findAnnotation或者AnnotatedElementUtils.findMergedAnnotation才能有效
注意事项
来自https://blog.csdn.net/weixin_43564627/article/details/93871075
1.组成别名对的每个属性都必须用@AliasFor进行注释,并且AliasFor中的值
必须指向别名对中的另一个属性
2.别名化的属性必须声明相同的返回类型
3.别名化的属性必须声明默认值
4.别名化的属性默认值必须相同
import org.springframework.core.annotation.AliasFor;
import java.lang.annotation.*;
/**
* @author lwh
* @date 2022/3/15
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AliasForAnnotation {
@AliasFor("location")
String value() default "";
@AliasFor("value")
String location() default "";
}
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.test.context.junit4.SpringRunner;
import java.lang.annotation.Annotation;
/**
* @author lwh
* @date 2022/3/15
*/
@AliasForAnnotation(location = "/spring/value")
public class AliasForTest {
@Test
public void test01(){
final AliasForAnnotation annotation = AnnotationUtils.findAnnotation(AliasForTest.class, AliasForAnnotation.class);
System.out.println(annotation.value());
System.out.println(annotation.location());
}
}
//输出
/spring/value
/spring/value
源码追踪
1.AnnotationUtils.findAnnotation
2.AnnotationUtils.synthesizeAnnotation
//返回别名值的策略,使用了策略模式
DefaultAnnotationAttributeExtractor attributeExtractor =
new DefaultAnnotationAttributeExtractor(annotation, annotatedElement);
//动态代理InvocationHandler ,传入返回别名值的策略。
InvocationHandler handler = new SynthesizedAnnotationInvocationHandler(attributeExtractor);
Class<?>[] exposedInterfaces = new Class<?>[] {annotationType, SynthesizedAnnotation.class};
//动态代理,使用了代理模式
return (A) Proxy.newProxyInstance(annotation.getClass().getClassLoader(), exposedInterfaces, handler);
3.使用动态代理,当执行被代理类时,会执行InvocationHandler 的invoke
//来自AnnotationUtils.synthesizeAnnotation
InvocationHandler handler = new SynthesizedAnnotationInvocationHandler(attributeExtractor);
//SynthesizedAnnotationInvocationHandler的invoke
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (ReflectionUtils.isEqualsMethod(method)) {
return annotationEquals(args[0]);
}
if (ReflectionUtils.isHashCodeMethod(method)) {
return annotationHashCode();
}
if (ReflectionUtils.isToStringMethod(method)) {
return annotationToString();
}
if (AnnotationUtils.isAnnotationTypeMethod(method)) {
return annotationType();
}
if (!AnnotationUtils.isAttributeMethod(method)) {
throw new AnnotationConfigurationException(String.format(
"Method [%s] is unsupported for synthesized annotation type [%s]", method, annotationType()));
}
return getAttributeValue(method);
}
4.SynthesizedAnnotationInvocationHandler.getAttributeValue
private Object getAttributeValue(Method attributeMethod) {
String attributeName = attributeMethod.getName();
Object value = this.valueCache.get(attributeName);
if (value == null) {
//this.attributeExtractor,不就是第2步传进来的返回别名值的策略吗?
value = this.attributeExtractor.getAttributeValue(attributeMethod);
if (value == null) {
String msg = String.format("%s returned null for attribute name [%s] from attribute source [%s]",
this.attributeExtractor.getClass().getName(), attributeName, this.attributeExtractor.getSource());
throw new IllegalStateException(msg);
}
if (value instanceof Annotation) {
value = AnnotationUtils.synthesizeAnnotation((Annotation) value, this.attributeExtractor.getAnnotatedElement());
}
else if (value instanceof Annotation[]) {
value = AnnotationUtils.synthesizeAnnotationArray((Annotation[]) value, this.attributeExtractor.getAnnotatedElement());
}
this.valueCache.put(attributeName, value);
}
// Clone arrays so that users cannot alter the contents of values in our cache.
if (value.getClass().isArray()) {
value = cloneArray(value);
}
return value;
}
5.DefaultAnnotationAttributeExtractor.getAttributeValue()
public final Object getAttributeValue(Method attributeMethod) {
String attributeName = attributeMethod.getName();
Object attributeValue = getRawAttributeValue(attributeMethod);
List<String> aliasNames = this.attributeAliasMap.get(attributeName);
if (aliasNames != null) {
Object defaultValue = AnnotationUtils.getDefaultValue(this.annotationType, attributeName);
for (String aliasName : aliasNames) {
Object aliasValue = getRawAttributeValue(aliasName);
if (!ObjectUtils.nullSafeEquals(attributeValue, aliasValue) &&
!ObjectUtils.nullSafeEquals(attributeValue, defaultValue) &&
!ObjectUtils.nullSafeEquals(aliasValue, defaultValue)) {
String elementName = (this.annotatedElement != null ? this.annotatedElement.toString() : "unknown element");
throw new AnnotationConfigurationException(String.format(
"In annotation [%s] declared on %s and synthesized from [%s], attribute '%s' and its " +
"alias '%s' are present with values of [%s] and [%s], but only one is permitted.",
this.annotationType.getName(), elementName, this.source, attributeName, aliasName,
ObjectUtils.nullSafeToString(attributeValue), ObjectUtils.nullSafeToString(aliasValue)));
}
if (ObjectUtils.nullSafeEquals(attributeValue, defaultValue)) {
//重点,需要的属性值=别名的属性值
attributeValue = aliasValue;
}
}
}
return attributeValue;
}
第二个例子
我们都知道注解是不能继承另一个注解的,当我们想复用某一个注解的属性时,根本无法做到,但是有了AliasFor,你可向另外一个注解注入属性值,请结合这个类使AnnotatedElementUtils.findMergedAnnotation,
注意事项
来自https://blog.csdn.net/weixin_43564627/article/details/93871075
1 如果一个属性是一个元注解属性的别名,那么这个属性必须用@AliasFor进行注释并且
该属性必须指向元注解属性。
2 别名化的属性必须声明相同的返回结果
3.@AliasFor的annotation属性必须引用元注解
4.被引用的元注解必须放置在声明了@AliasFor的注解类上
import org.springframework.core.annotation.AliasFor;
import java.lang.annotation.*;
/**
* @author lwh
* @date 2022/3/16
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LocationAnnotation {
@AliasFor("value")
String location() default "";
@AliasFor("location")
String value() default "";
}
import org.springframework.core.annotation.AliasFor;
import java.lang.annotation.*;
/**
* @author lwh
* @date 2022/3/15
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@LocationAnnotation //我使用了这个注解,我希望可以赋值给它
public @interface AliasForAnnotation {
//当向value赋值时,LocationAnnotation的location属性也会赋予到值
@AliasFor(attribute = "location",annotation = LocationAnnotation.class )
String value() default "";
}
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.test.context.junit4.SpringRunner;
import java.lang.annotation.Annotation;
/**
* @author lwh
* @date 2022/3/15
*/
@AliasForAnnotation( "/spring/value")
public class AliasForTest {
@Test
public void test01(){
final LocationAnnotation annotation = AnnotatedElementUtils.findMergedAnnotation(AliasForTest.class, LocationAnnotation.class);
System.out.println(annotation.location());
}
}
源码追踪(简单的跟了一下,具体的可以自己查看,凌晨4.23,哭了)
简单的说,就是递归获取到LocationAnnotation 注解,然后获取到AliasForAnnotation 的value值,封装成map,然后把这个值传到MapAnnotationAttributeExtractor里这个值经过一些判断和处理,然后进行动态代理,最后通过MapAnnotationAttributeExtractor的getAttributeValue获取到值,getAttributeValue其实获取的是之前传过来的值
1. AnnotatedElementUtils.findMergedAnnotation
2. AnnotatedElementUtils.findMergedAnnotationAttributes
3. AnnotatedElementUtils.searchWithFindSemantics
4.AnnotatedElementUtils.searchWithFindSemantics//递归查找,直到查找到LocationAnnotation 注解
5.MergedAnnotationAttributesProcessor.postProcess
6.MergedAnnotationAttributesProcessor.overrideAttributes
7. AnnotationUtils.synthesizeAnnotation(attributes, annotationType, element),换了MapAnnotationAttributeExtractor策略来处理别名值
8. SynthesizedAnnotationInvocationHandler(attributeExtractor),动态代理执行invoke()
执行MapAnnotationAttributeExtractor策略的方法
9.MapAnnotationAttributeExtractor没有getAttributeValue方法,使用父类AbstractAliasAwareAnnotationAttributeExtractor的方法
参考文章
https://blog.csdn.net/weixin_43564627/article/details/93871075