同步操作将从 huifer/Code-Analysis 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
本章笔者将围绕 org.springframework.core.type.AnnotationMetadata
接口和各位读者一起探讨它做了什么。
注解元数据的接口是 AnnotationMetadata
,我们先来看这个接口的类图
AnnotationMetadata
类图从这个类图中我们可以看到注解元数据由三个接口提供,对于 ClassMetadata
中定义了那些方法各位可以翻阅第二十五章,下面我们来看其他两个接口的方法
AnnotatedTypeMetadata
接口说明AnnotatedTypeMetadata
详细信息public interface AnnotatedTypeMetadata {
/**
* 获取所有注解
*/
MergedAnnotations getAnnotations();
/**
* 是否有注解, 是否被参数注解修饰
*/
default boolean isAnnotated(String annotationName) {
return getAnnotations().isPresent(annotationName);
}
/**
* 获取注解的属性
*/
@Nullable
default Map<String, Object> getAnnotationAttributes(String annotationName) {
return getAnnotationAttributes(annotationName, false);
}
/**
* 获取注解属性表
*/
@Nullable
default Map<String, Object> getAnnotationAttributes(String annotationName,
boolean classValuesAsString) {
MergedAnnotation<Annotation> annotation = getAnnotations().get(annotationName,
null, MergedAnnotationSelectors.firstDirectlyDeclared());
if (!annotation.isPresent()) {
return null;
}
return annotation.asAnnotationAttributes(Adapt.values(classValuesAsString, true));
}
/**
* 获取注解的属性表
*/
@Nullable
default MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName) {
return getAllAnnotationAttributes(annotationName, false);
}
/**
* 获取注解属性表
*/
@Nullable
default MultiValueMap<String, Object> getAllAnnotationAttributes(
String annotationName, boolean classValuesAsString) {
Adapt[] adaptations = Adapt.values(classValuesAsString, true);
return getAnnotations().stream(annotationName)
.filter(MergedAnnotationPredicates.unique(MergedAnnotation::getMetaTypes))
.map(MergedAnnotation::withNonMergedAttributes)
.collect(MergedAnnotationCollectors.toMultiValueMap(map ->
map.isEmpty() ? null : map, adaptations));
}
}
方法名称 | 方法返回值 | 方法参数 | 方法作用 |
---|---|---|---|
getAnnotations |
MergedAnnotations |
提取注解集合 | |
isAnnotated |
boolean |
annotationName :注解名称 |
判断是否存在该注解 |
getAnnotationAttributes |
Map<String, Object> |
annotationName :注解名称 |
获取指定注解的属性表 |
AnnotationMetadata
接口说明public interface AnnotationMetadata extends ClassMetadata, AnnotatedTypeMetadata {
/**
* 获取注解名称,全类名
*/
default Set<String> getAnnotationTypes() {
return getAnnotations().stream()
// 判断是否直接使用注解
.filter(MergedAnnotation::isDirectlyPresent)
// 获取注解的名字
.map(annotation -> annotation.getType().getName())
// 转换成set
.collect(Collectors.toCollection(LinkedHashSet::new));
}
/**
* 注解全类名
*/
default Set<String> getMetaAnnotationTypes(String annotationName) {
// 获取注解合并后的结果
MergedAnnotation<?> annotation = getAnnotations().get(annotationName, MergedAnnotation::isDirectlyPresent);
// 判断注解是否使用
if (!annotation.isPresent()) {
// 不使用直接返回空
return Collections.emptySet();
}
// 注解使用 继承查找获得所有注解名称(类名)
return MergedAnnotations.from(annotation.getType(), SearchStrategy.INHERITED_ANNOTATIONS).stream()
.map(mergedAnnotation -> mergedAnnotation.getType().getName())
.collect(Collectors.toCollection(LinkedHashSet::new));
}
/**
* 是否包含某个注解
*/
default boolean hasAnnotation(String annotationName) {
return getAnnotations().isDirectlyPresent(annotationName);
}
/**
* 是否被某个注解标记过
*/
default boolean hasMetaAnnotation(String metaAnnotationName) {
return getAnnotations().get(metaAnnotationName,
MergedAnnotation::isMetaPresent).isPresent();
}
/**
* 是否有注解,类里面有一个注解就返回true
*/
default boolean hasAnnotatedMethods(String annotationName) {
return !getAnnotatedMethods(annotationName).isEmpty();
}
/**
* 获取包含注解的方法
*/
Set<MethodMetadata> getAnnotatedMethods(String annotationName);
/**
* 通过反射创建一个注解的元信息
*/
static AnnotationMetadata introspect(Class<?> type) {
return StandardAnnotationMetadata.from(type);
}
}
方法名称 | 方法返回值 | 方法说明 |
---|---|---|
getAnnotationTypes |
Set<String> |
获取注解类名列表 |
getMetaAnnotationTypes |
Set<String> |
获取一个类型的注解名称列表 |
hasAnnotation |
boolean |
是否存直接存在某个注解 |
hasMetaAnnotation |
boolean |
是否存在某个注解 |
hasAnnotatedMethods |
boolean |
是否存在某个注解 |
getAnnotatedMethods |
Set<MethodMetadata> |
获取注解属性 |
introspect |
AnnotationMetadata |
构造器提供AnnotationMetadata 初始化方法 |
这里我们需要对直接存在某个注解和是否存在某个注解做出解释。下面笔者将使用 Component
注解和 Configuration
来做出演示
我们可以定义下面两个类
@Component
public class A {
}
@Configuration
public class C {
}
之后我们来编写测试代码
@Test
void testAnn() {
AnnotationMetadata introspect = AnnotationMetadata.introspect(C.class);
System.out.println(introspect.hasAnnotation(Component.class.getName()));
System.out.println(introspect.hasMetaAnnotation(Component.class.getName()));
}
这个测试代码会输出
false
true
Component
注解是间接被引用的,它在 Configuration
上被使用了具体代码如下
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {}
通过这样一个例子我们来对 hasAnnotation
方法和 hasMetaAnnotation
方法的差异做出了解。
StandardAnnotationMetadata
分析我们在 AnnotationMetadata
中可以找到 introspect
方法,在这个方法中指向了一个类,这个类提供了注解元数据的处理能力。
先来看这个类的成员变量
变量名称 | 变量类型 | 变量说明 |
---|---|---|
mergedAnnotations |
MergedAnnotations |
合并的注解属性 |
nestedAnnotationsAsMap |
boolean |
是否需要将注解属性做成嵌套的map对象 |
annotationTypes |
Set<String> |
注解类型列表 |
下面我们来看它的构造方法
@Deprecated
public StandardAnnotationMetadata(Class<?> introspectedClass, boolean nestedAnnotationsAsMap) {
super(introspectedClass);
this.mergedAnnotations = MergedAnnotations.from(introspectedClass,
SearchStrategy.INHERITED_ANNOTATIONS, RepeatableContainers.none(),
AnnotationFilter.NONE);
this.nestedAnnotationsAsMap = nestedAnnotationsAsMap;
}
mergedAnnotations
数据信息在这个成员变量中得到的 mergedAnnotations
数据将为后续的注解方法使用提供基础数据内容。下面我们来看一个提取注解属性的操作,具体代码如下。
@Nullable
default Map<String, Object> getAnnotationAttributes(String annotationName,
boolean classValuesAsString) {
MergedAnnotation<Annotation> annotation = getAnnotations().get(annotationName,
null, MergedAnnotationSelectors.firstDirectlyDeclared());
if (!annotation.isPresent()) {
return null;
}
return annotation.asAnnotationAttributes(Adapt.values(classValuesAsString, true));
}
在这个方法中出现的操作如下
mergedAnnotations
中的指定注解的注解信息@ComponentScans(
value = {
@ComponentScan()
}
)
在这个处理过程中我们的本质是为了得到注解的数据,本文先不讨论 Spring 中的处理方式,我们先来看 Java 中如何得到这样的一个数据
下面我们以 Component
为例来制作注解的数据解析方法
第一步创建一个对象
@Component(value = "abcd")
public class A {
}
第二步编写逻辑代码
@Test
void annAttribute() throws InvocationTargetException, IllegalAccessException {
A a = new A();
Class<? extends A> aClass = a.getClass();
Annotation[] annotations = aClass.getAnnotations();
Map<String, Map<String, Object>> annotationAttributes = new HashMap<>();
for (Annotation annotation : annotations) {
Class<? extends Annotation> annClass = annotation.annotationType();
String name = annClass.getName();
Method[] declaredMethods = annClass.getDeclaredMethods();
Map<String, Object> oneAnnotationAttributes = new HashMap<>();
for (Method declaredMethod : declaredMethods) {
String annAtrrName = declaredMethod.getName();
Object invoke = declaredMethod.invoke(annotation);
oneAnnotationAttributes.put(annAtrrName, invoke);
}
annotationAttributes.put(name, oneAnnotationAttributes);
}
System.out.println();
}
逻辑代码编写完成后我们来看看 annotationAttributes
变量中存储了什么内容
annotationAttributes
是一个Map结构
第一层
key:主界名称
value:注解数据
第二层
key:注解属性名称
value:注解属性值
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。