栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

如何判断某个类是否有某个注解?

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

如何判断某个类是否有某个注解?

开发过程中,我们经常通过在类上打注解的方式来给它做标记,以便后期对其进行相应操作。

比如Springboot在启动的时候,会对标有@Component注解的类进行加载和初始化。

那么,如何判断某个类是否有某个注解呢?

很多人会说,这还不简单,不就是利用反射检索该类的注解集合里有没有这个注解不就好了吗。

但这样是不全面的,因为类可能继承自某个父类或者接口,而其父类或者接口上存在该注解。

同时,该注解可能是个复合注解,即该注解也是被其他注解所注解的。

所以,判断某个类是否有某个注解的完善流程应该包含4个方面:

检索该类是否直接被该注解标记;递归检索该类注解的注解中是否存在目标注解;递归检索该类的接口中是否存在目标注解;递归检索该类的父类是否存在目标注解。

Spring框架的AnnotationUtils.findAnnotation方法就是基于上述流程来实现的。

private static  A findAnnotation(Class clazz, Class annotationType, Set visited) {
	try {
		// 判断该类是否被该注解直接标记,对应第①种情况
		A annotation = clazz.getDeclaredAnnotation(annotationType);
		if (annotation != null) {
			return annotation;
		}
		// 递归检索该类注解的注解中是否存在目标注解,对应第②种情况
		for (Annotation declaredAnn : clazz.getDeclaredAnnotations()) {
			Class declaredType = declaredAnn.annotationType();
			if (!isInJavaLangAnnotationPackage(declaredType) && visited.add(declaredAnn)) {
				// 进入递归
				annotation = findAnnotation(declaredType, annotationType, visited);
				if (annotation != null) {
					return annotation;
				}
			}
		}
	}
	catch (Throwable ex) {
		handleIntrospectionFailure(clazz, ex);
		return null;
	}
	// 递归检索该类的接口中是否存在目标注解,对应第③种情况
	for (Class ifc : clazz.getInterfaces()) {
		A annotation = findAnnotation(ifc, annotationType, visited);
		if (annotation != null) {
			return annotation;
		}
	}
	// 递归检索该类的父类是否存在目标注解,对应第④种情况
	Class superclass = clazz.getSuperclass();
	// 如果父类不存在或者父类为Object,则直接返回null
	if (superclass == null || Object.class == superclass) {
		return null;
	}
	return findAnnotation(superclass, annotationType, visited);
}

同时,AnnotationUtils会通过缓存来加快检索速度。

private static  A findAnnotation(
		Class clazz, @Nullable Class annotationType, boolean synthesize) {

	Assert.notNull(clazz, "Class must not be null");
	if (annotationType == null) {
		return null;
	}

	AnnotationCacheKey cacheKey = new AnnotationCacheKey(clazz, annotationType);
	// 若缓存中存在,则直接返回
	A result = (A) findAnnotationCache.get(cacheKey);
	if (result == null) {
		// 否则执行注解检索,即上面讲过的4个过程
		result = findAnnotation(clazz, annotationType, new HashSet<>());
		if (result != null && synthesize) {
			result = synthesizeAnnotation(result, clazz);
			// 将结果更新到缓存中
			findAnnotationCache.put(cacheKey, result);
		}
	}
	return result;
}

缓存是使用ConcurrentReferenceHashMap来作为容器的,其和ConcurrentHashMap不同的是,ConcurrentReferenceHashMap可以声明容器对象的引用强度,默认使用的是软连接,即当内存不足时,会被GC强制回收,避免OOM。

可以看出,仅仅判断某个类是否有某个注解这样1个简单的需求,我们想要做的完善,代码写的健壮,也不是一件简单的事情。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/736146.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号