spring core:@AliasFor的派生性

作者 : 前沿资讯 本文共6725个字,预计阅读时间需要17分钟 发布时间: 2020-03-9 共417人阅读

spring对Annotation的派生性应用可谓炉火纯青,在spring core:@Component的派生性讲过支持层次上派生性,而属性上派生的需求则借助了@AliasFor,它是从spring4.2中开始支持的。

@AliasFor注解用于声明注解元素的别名,应用于方法上(别忘了注解本质是接口)。Spring框架在内部使用大量的使用这个注解,例如,@Bean@ComponentScan@Scope等。

 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Documented public @interface AliasFor { 	/** 	 * 	 * 引用的注解别名.. 	 */ 	@AliasFor("attribute") 	String value() default ""; 	/** 	 * 引用的注解别名. 	 * @see #value 	 */ 	@AliasFor("value") 	String attribute() default ""; 	/**层次结构的父注解 	 */ 	Class<? extends Annotation> annotation() default Annotation.class; }

示例1

可通过AnnotatedElementUtils#getMergedAnnotationAttributes来读取。下面演示没有派生性的情况:

 @Test public void metaTest() throws IOException {     AnnotationAttributes aa = AnnotatedElementUtils.getMergedAnnotationAttributes(Home.class, AccessRole.class);     System.out.println(aa);//{value=super-user, module=gui, accessType=super-user} } @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface AccessRole {     @AliasFor("accessType")     String value() default "visitor";      @AliasFor("value")     String accessType() default "visitor";      String module() default "gui"; } @AccessRole("super-user") //@AccessRole(value = "super-user",accessType = "super")//error public class Home { }

注:alias references的默认值必须一致,使用时指定值也必须一致,否则会抛出AnnotationConfigurationException

下面演示有单层次及多层次派生性的情况:

 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @AccessRole("admin") public @interface AdminAccess {     @AliasFor(annotation = AccessRole.class, attribute = "module")     String value() default "service"; } @AdminAccess public class Home2 { } @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @AdminAccess("supper") public @interface SupperAccess {     String value() default "service3";     @AliasFor(annotation = AccessRole.class, attribute = "module")     String module() default "service3"; } @SupperAccess public class Home3 { } @Test public void metaTest() throws IOException {     AnnotationAttributes aa = AnnotatedElementUtils.getMergedAnnotationAttributes(Home2.class, AdminAccess.class);     System.out.println(aa);//{value=service}     aa = AnnotatedElementUtils.getMergedAnnotationAttributes(Home2.class, AccessRole.class);     System.out.println(aa);//{value=admin, accessType=admin, module=service}     aa = AnnotatedElementUtils.getMergedAnnotationAttributes(Home3.class, AccessRole.class);     System.out.println(aa);//{value=admin, module=service3, accessType=admin} }

原理

AnnotatedElementUtils处理也不是特别复杂,很好理解

 public abstract class AnnotatedElementUtils { 	@Nullable 	public static AnnotationAttributes getMergedAnnotationAttributes( 			AnnotatedElement element, Class<? extends Annotation> annotationType) {  		AnnotationAttributes attributes = searchWithGetSemantics(element, annotationType, null, 				new MergedAnnotationAttributesProcessor()); 		AnnotationUtils.postProcessAnnotationAttributes(element, attributes, false, false); 		return attributes; 	}     //第一步:searchWithGetSemantics真正调用的方法,递归获取所有的注解 	@Nullable 	private static <T> T searchWithGetSemantics(AnnotatedElement element, 			Set<Class<? extends Annotation>> annotationTypes, @Nullable String annotationName, 			@Nullable Class<? extends Annotation> containerType, Processor<T> processor, 			Set<AnnotatedElement> visited, int metaDepth) {  		if (visited.add(element)) { 			try { 				// Start searching within locally declared annotations 				List<Annotation> declaredAnnotations = Arrays.asList(AnnotationUtils.getDeclaredAnnotations(element)); 				T result = searchWithGetSemanticsInAnnotations(element, declaredAnnotations, 						annotationTypes, annotationName, containerType, processor, visited, metaDepth); 				if (result != null) { 					return result; 				}  				if (element instanceof Class) {  // otherwise getAnnotations doesn't return anything new 					Class<?> superclass = ((Class<?>) element).getSuperclass(); 					if (superclass != null && superclass != Object.class) { 						List<Annotation> inheritedAnnotations = new LinkedList<>(); 						for (Annotation annotation : element.getAnnotations()) { 							if (!declaredAnnotations.contains(annotation)) { 								inheritedAnnotations.add(annotation); 							} 						} 						// Continue searching within inherited annotations 						result = searchWithGetSemanticsInAnnotations(element, inheritedAnnotations, 								annotationTypes, annotationName, containerType, processor, visited, metaDepth); 						if (result != null) { 							return result; 						} 					} 				} 			} 			catch (Throwable ex) { 				AnnotationUtils.handleIntrospectionFailure(element, ex); 			} 		}  		return null; 	} } public abstract class AnnotationUtils {     //第二步:获取@AliasFor的标记,处理其值 	static void postProcessAnnotationAttributes(@Nullable Object annotatedElement, 			@Nullable AnnotationAttributes attributes, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {  		if (attributes == null) { 			return; 		}  		Class<? extends Annotation> annotationType = attributes.annotationType();  		// Track which attribute values have already been replaced so that we can short 		// circuit the search algorithms. 		Set<String> valuesAlreadyReplaced = new HashSet<>();  		if (!attributes.validated) { 			// Validate @AliasFor configuration 			Map<String, List<String>> aliasMap = getAttributeAliasMap(annotationType); 			aliasMap.forEach((attributeName, aliasedAttributeNames) -> { 				if (valuesAlreadyReplaced.contains(attributeName)) { 					return; 				} 				Object value = attributes.get(attributeName); 				boolean valuePresent = (value != null && !(value instanceof DefaultValueHolder)); 				for (String aliasedAttributeName : aliasedAttributeNames) { 					if (valuesAlreadyReplaced.contains(aliasedAttributeName)) { 						continue; 					} 					Object aliasedValue = attributes.get(aliasedAttributeName); 					boolean aliasPresent = (aliasedValue != null && !(aliasedValue instanceof DefaultValueHolder)); 					// Something to validate or replace with an alias? 					if (valuePresent || aliasPresent) { 						if (valuePresent && aliasPresent) { 							// Since annotation attributes can be arrays, we must use ObjectUtils.nullSafeEquals(). 							if (!ObjectUtils.nullSafeEquals(value, aliasedValue)) { 								String elementAsString = 										(annotatedElement != null ? annotatedElement.toString() : "unknown element"); 								throw new AnnotationConfigurationException(String.format( 										"In AnnotationAttributes for annotation [%s] declared on %s, " + 										"attribute '%s' and its alias '%s' are declared with values of [%s] and [%s], " + 										"but only one is permitted.", attributes.displayName, elementAsString, 										attributeName, aliasedAttributeName, ObjectUtils.nullSafeToString(value), 										ObjectUtils.nullSafeToString(aliasedValue))); 							} 						} 						else if (aliasPresent) { 							// Replace value with aliasedValue 							attributes.put(attributeName, 									adaptValue(annotatedElement, aliasedValue, classValuesAsString, nestedAnnotationsAsMap)); 							valuesAlreadyReplaced.add(attributeName); 						} 						else { 							// Replace aliasedValue with value 							attributes.put(aliasedAttributeName, 									adaptValue(annotatedElement, value, classValuesAsString, nestedAnnotationsAsMap)); 							valuesAlreadyReplaced.add(aliasedAttributeName); 						} 					} 				} 			}); 			attributes.validated = true; 		}  		// Replace any remaining placeholders with actual default values 		for (Map.Entry<String, Object> attributeEntry : attributes.entrySet()) { 			String attributeName = attributeEntry.getKey(); 			if (valuesAlreadyReplaced.contains(attributeName)) { 				continue; 			} 			Object value = attributeEntry.getValue(); 			if (value instanceof DefaultValueHolder) { 				value = ((DefaultValueHolder) value).defaultValue; 				attributes.put(attributeName, 						adaptValue(annotatedElement, value, classValuesAsString, nestedAnnotationsAsMap)); 			} 		} 	} }

待续spring core:@AliasFor的派生性

  • 版权声明:文章来源于网络采集,版权归原创者所有,均已注明来源,如未注明可能来源未知,如有侵权请联系管理员删除。
1. 本站所有资源来源于网络和用户上传,如有侵权请联系站长或邮件至6788335@qq.com
2. 本站分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,商用请支持正版!不得违反国家法律,否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!

小七博客 » spring core:@AliasFor的派生性

Leave a Reply

售后服务:

  • 售后服务范围 1、商业模板使用范围内问题免费咨询
    2、源码安装、模板安装(一般 ¥50-300)服务答疑仅限SVIP用户
    3、单价超过200元的模板免费一次安装,需提供服务器信息。
    付费增值服务 1、提供dedecms模板、WordPress主题、discuz模板优化等服务请详询在线客服
    2、承接 WordPress、DedeCMS、Discuz 等系统建站、仿站、开发、定制等服务
    3、服务器环境配置(一般 ¥50-300)
    4、网站中毒处理(需额外付费,500元/次/质保三个月)
    售后服务时间 周一至周日(法定节假日除外) 9:00-23:00
    免责声明 本站所提供的模板(主题/插件)等资源仅供学习交流,若使用商业用途,请购买正版授权,否则产生的一切后果将由下载用户自行承担,有部分资源为网上收集或仿制而来,若模板侵犯了您的合法权益,请来信通知我们(Email: 6788335@qq.com),我们会及时删除,给您带来的不便,我们深表歉意!

Hi, 如果你对这款模板有疑问,可以跟我联系哦!

联系作者
赞助VIP 享更多特权,建议使用 QQ 登录
喜欢我嘛?喜欢就按“ctrl+D”收藏我吧!♡