目錄
2. SynthesizedAnnotationInvocationHandler創建和執行邏輯
2.1 DefaultAnnotationAttributeExtractor
2.1.1 AbstractAliasAwareAnnotationAttributeExtractor構造函數
2.2 SynthesizedAnnotationInvocationHandler執行邏輯
我們在使用註解或者自定義註解時,有時經常看到在註解方法上標註註解@AliasFor,見名知義,這是一種爲註解屬性定義別名的註解實現方式,這樣在不同的場合賦值不同的屬性,但獲取兩個屬性值時是一樣的,這裏的實現原理實際上也是JDK動態代理的過程,下面對該代理過程進行分析;
0. 源碼參見
@AliasFor 具體工作機制源碼參見AnnotationUtils.synthesizeAnnotation(A annotation, Object annotatedElement) 方法:
/**
* <em>Synthesize</em> an annotation from the supplied {@code annotation}
* by wrapping it in a dynamic proxy that transparently enforces
* <em>attribute alias</em> semantics for annotation attributes that are
* annotated with {@link AliasFor @AliasFor}.
* @param annotation the annotation to synthesize
* @param annotatedElement the element that is annotated with the supplied
* annotation; may be {@code null} if unknown
* @return the synthesized annotation if the supplied annotation is
* <em>synthesizable</em>; {@code null} if the supplied annotation is
* {@code null}; otherwise the supplied annotation unmodified
* @throws AnnotationConfigurationException if invalid configuration of
* {@code @AliasFor} is detected
* @since 4.2
* @see #synthesizeAnnotation(Map, Class, AnnotatedElement)
* @see #synthesizeAnnotation(Class)
*/
public static <A extends Annotation> A synthesizeAnnotation(A annotation, AnnotatedElement annotatedElement) {
return synthesizeAnnotation(annotation, (Object) annotatedElement);
}
@SuppressWarnings("unchecked")
static <A extends Annotation> A synthesizeAnnotation(A annotation, Object annotatedElement) {
if (annotation == null) {
return null;
}
if (annotation instanceof SynthesizedAnnotation) {
return annotation;
}
Class<? extends Annotation> annotationType = annotation.annotationType();
if (!isSynthesizable(annotationType)) {
return annotation;
}
DefaultAnnotationAttributeExtractor attributeExtractor =
new DefaultAnnotationAttributeExtractor(annotation, annotatedElement);
InvocationHandler handler = new SynthesizedAnnotationInvocationHandler(attributeExtractor);
// Can always expose Spring's SynthesizedAnnotation marker since we explicitly check for a
// synthesizable annotation before (which needs to declare @AliasFor from the same package)
Class<?>[] exposedInterfaces = new Class<?>[] {annotationType, SynthesizedAnnotation.class};
return (A) Proxy.newProxyInstance(annotation.getClass().getClassLoader(), exposedInterfaces, handler);
}
這裏的處理過程包含如下幾步:
- 如果已經是SynthesizedAnnotation實現類,即已經是代理類,直接返回;
- isSynthesizable判斷該註解是不是標註了@AliasFor註解,是否需要被代理;
- 創建SynthesizedAnnotationInvocationHandler,這是一個InvocationHandler類,用於構造JDK動態代理
- 創建JDK動態代理
下面主要分析下2~4步;
1. isSynthesizable判斷是否需要被代理
具體代碼如下:
/**
* Determine if annotations of the supplied {@code annotationType} are
* <em>synthesizable</em> (i.e., in need of being wrapped in a dynamic
* proxy that provides functionality above that of a standard JDK
* annotation).
* <p>Specifically, an annotation is <em>synthesizable</em> if it declares
* any attributes that are configured as <em>aliased pairs</em> via
* {@link AliasFor @AliasFor} or if any nested annotations used by the
* annotation declare such <em>aliased pairs</em>.
* @since 4.2
* @see SynthesizedAnnotation
* @see SynthesizedAnnotationInvocationHandler
*/
@SuppressWarnings("unchecked")
private static boolean isSynthesizable(Class<? extends Annotation> annotationType) {
Boolean synthesizable = synthesizableCache.get(annotationType);
if (synthesizable != null) {
return synthesizable;
}
synthesizable = Boolean.FALSE;
for (Method attribute : getAttributeMethods(annotationType)) {
if (!getAttributeAliasNames(attribute).isEmpty()) {
synthesizable = Boolean.TRUE;
break;
}
Class<?> returnType = attribute.getReturnType();
if (Annotation[].class.isAssignableFrom(returnType)) {
Class<? extends Annotation> nestedAnnotationType =
(Class<? extends Annotation>) returnType.getComponentType();
if (isSynthesizable(nestedAnnotationType)) {
synthesizable = Boolean.TRUE;
break;
}
}
else if (Annotation.class.isAssignableFrom(returnType)) {
Class<? extends Annotation> nestedAnnotationType = (Class<? extends Annotation>) returnType;
if (isSynthesizable(nestedAnnotationType)) {
synthesizable = Boolean.TRUE;
break;
}
}
}
synthesizableCache.put(annotationType, synthesizable);
return synthesizable;
}
這裏主要判斷依據分爲兩點:
- 該註解屬性上直接標註了AliasFor註解;
- 屬性返回值爲註解類型且標註了AliasFor註解,該部分的解析是通過遞歸來解析的;
2. SynthesizedAnnotationInvocationHandler創建和執行邏輯
在SynthesizedAnnotationInvocationHandler構造時,首先創建了一個DefaultAnnotationAttributeExtractor,下面首先看一下該類的功能實現,然後再分析SynthesizedAnnotationInvocationHandler的執行過程;
2.1 DefaultAnnotationAttributeExtractor
其繼承結構類圖如下:
接口AnnotationAttributeExtractor是一個註解屬性提取器,主要用來獲取註解的屬性;
AbstractAliasAwareAnnotationAttributeExtractor實現了該接口,主要用於獲取標註AliasFor註解的屬性值;
DefaultAnnotationAttributeExtractor提供了實際獲取屬性值的反射調用方法;
在AbstractAliasAwareAnnotationAttributeExtractor抽象類中,核心邏輯都在構造函數以及getAttributeValue接口方法中,下面分別看下這兩個方法的實現:
2.1.1 AbstractAliasAwareAnnotationAttributeExtractor構造函數
構造函數實現如下:
/**
* Construct a new {@code AbstractAliasAwareAnnotationAttributeExtractor}.
* @param annotationType the annotation type to synthesize; never {@code null}
* @param annotatedElement the element that is annotated with the annotation
* of the supplied type; may be {@code null} if unknown
* @param source the underlying source of annotation attributes; never {@code null}
*/
AbstractAliasAwareAnnotationAttributeExtractor(
Class<? extends Annotation> annotationType, Object annotatedElement, S source) {
Assert.notNull(annotationType, "annotationType must not be null");
Assert.notNull(source, "source must not be null");
this.annotationType = annotationType;
this.annotatedElement = annotatedElement;
this.source = source;
this.attributeAliasMap = AnnotationUtils.getAttributeAliasMap(annotationType);
}
最後一行用來獲取原屬性名和別名屬性名之間的對應關係,具體不再展開,實際獲取別名主要包含兩個:
- 註解類直接包含了兩個互爲別名的屬性;
- 註解類中兩個屬性的別名同爲該註解元註解的某個屬性,這樣兩個屬性互爲間接別名;
2.1.2 接口方法getAttributeValue
該接口方法主要獲取直接屬性值與所有別名屬性值,並排除默認屬性值之後,返回註解屬性值,具體實現如下:
@Override
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 the user didn't declare the annotation with an explicit value,
// use the value of the alias instead.
if (ObjectUtils.nullSafeEquals(attributeValue, defaultValue)) {
attributeValue = aliasValue;
}
}
}
return attributeValue;
}
2.2 SynthesizedAnnotationInvocationHandler執行邏輯
在接口方法invoke中,代理原目標方法,通過DefaultAnnotationAttributeExtractor獲取屬性值,這樣就綜合考慮了原屬性值和別名屬性值的作用,如下:
@Override
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);
}
private Object getAttributeValue(Method attributeMethod) {
String attributeName = attributeMethod.getName();
Object value = this.valueCache.get(attributeName);
if (value == null) {
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);
}
// Synthesize nested annotations before returning them.
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;
}
3. 創建JDK動態代理
創建JDK動態代理還是通過Proxy.newProxyInstance來實現的,在目標接口中加入了SynthesizedAnnotation接口,該接口是一個marker接口,表示是否已經解析爲代理對象;
Class<?>[] exposedInterfaces = new Class<?>[] {annotationType, SynthesizedAnnotation.class}; (A) Proxy.newProxyInstance(annotation.getClass().getClassLoader(), exposedInterfaces, handler);