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));
+ }
+
+ /**
+ * 确定给定类型的注解是否 存在 在底层类上。
+ * @param annotationName 要查找的注解类型的完全限定类名
+ * @return 如果存在匹配的注解则返回 {@code true}
+ */
+ default boolean hasAnnotation(String annotationName) {
+ return getAnnotations().isDirectlyPresent(annotationName);
+ }
+
+ /**
+ * 确定底层类是否具有其本身带有给定类型的元注解的注解。
+ * @param metaAnnotationName 要查找的元注解类型的完全限定类名
+ * @return 如果存在匹配的元注解则返回 {@code true}
+ */
+ default boolean hasMetaAnnotation(String metaAnnotationName) {
+ return getAnnotations().get(metaAnnotationName,
+ MergedAnnotation::isMetaPresent).isPresent();
+ }
+
+ /**
+ * 确定底层类是否具有任何方法带有给定注解类型(或带有元注解的)。
+ * @param annotationName 要查找的注解类型的完全限定类名
+ */
+ default boolean hasAnnotatedMethods(String annotationName) {
+ return !getAnnotatedMethods(annotationName).isEmpty();
+ }
+
+ /**
+ * 检索带有给定注解类型(或带有元注解的)的所有方法的方法元数据。
+ * 对于任何返回的方法,{@link MethodMetadata#isAnnotated} 将对给定的注解类型返回 {@code true}。
+ * @param annotationName 要查找的注解类型的完全限定类名
+ * @return 具有匹配注解的方法的{@link MethodMetadata}集合。如果没有方法匹配注解类型,则返回空集合。
+ */
+ Set getAnnotatedMethods(String annotationName);
+
+ /**
+ * 使用标准反射创建一个新的 {@link AnnotationMetadata} 实例的工厂方法,用于给定的类。
+ * @param type 要分析的类
+ * @return 新的 {@link AnnotationMetadata} 实例
+ * @since 5.2
+ */
+ static AnnotationMetadata introspect(Class> type) {
+ return StandardAnnotationMetadata.from(type);
+ }
+}
+```
+
+### 五、主要实现
+
+1. **StandardAnnotationMetadata**:
+ - 这个实现依赖于标准的 Java 反射机制,它使用 Java 的 `java.lang.Class` 对象来分析和访问类的注解信息。
+ - 通过这个实现,我们可以轻松地检查类上的注解、获取注解属性值以及执行其他与注解相关的操作。
+2. **SimpleAnnotationMetadata**:
+ - 是一个基于 ASM(字节码操作库)的实现,用于分析和访问类的注解信息。相比于 `StandardAnnotationMetadata`,它通常更轻量,不依赖于标准 Java 反射机制,而是直接解析类的字节码。
+
+~~~mermaid
+classDiagram
+ direction BT
+
+ class ClassMetadata {
+ <>
+ }
+
+ class AnnotatedTypeMetadata {
+ <>
+ }
+
+ class AnnotationMetadata {
+ <>
+ }
+
+ class StandardClassMetadata {
+ }
+
+ class SimpleAnnotationMetadata {
+ }
+
+ class StandardAnnotationMetadata {
+ }
+
+ AnnotationMetadata ..|> ClassMetadata
+ AnnotationMetadata ..|> AnnotatedTypeMetadata
+ SimpleAnnotationMetadata --|> AnnotationMetadata
+ StandardClassMetadata --|> ClassMetadata
+ StandardAnnotationMetadata ..|> StandardClassMetadata
+ StandardAnnotationMetadata --|> AnnotationMetadata
+
+~~~
+
+### 六、最佳实践
+
+#### ASM字节码技术
+
+我们使用 ASM 字节码技术创建了一个 `AnnotationMetadata` 对象,通过创建 `MetadataReaderFactory` 和 `MetadataReader` 对象,加载了名为 "`com.xcs.spring.bean.MyBean`" 的类的元数据,然后通过 `AnnotationMetadata` 检查是否被 `@Component` 注解标记,并获取注解属性值,最后输出相应的结果。这个过程允许在不实际加载类的情况下,动态地分析和操作类的注解信息。
+
+```java
+public class AnnotationMetadataDemoByASM {
+
+ public static void main(String[] args) throws Exception {
+ // 创建 MetadataReaderFactory
+ SimpleMetadataReaderFactory readerFactory = new SimpleMetadataReaderFactory();
+ // 获取 MetadataReader
+ MetadataReader metadataReader = readerFactory.getMetadataReader("com.xcs.spring.bean.MyBean");
+
+ // 获取 AnnotationMetadata
+ AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
+
+ System.out.println("AnnotationMetadata impl class is " + annotationMetadata.getClass());
+
+ // 检查 MyBean 类是否被 @Component 注解标记
+ boolean isComponent = annotationMetadata.hasAnnotation(Component.class.getName());
+ System.out.println("MyBean is a @Component: " + isComponent);
+
+ // 获取 MyBean 类上的注解属性
+ if (isComponent) {
+ Map annotationAttributes = annotationMetadata.getAnnotationAttributes(Component.class.getName());
+ System.out.println("@Component value is " + annotationAttributes.get("value"));
+ }
+ }
+}
+```
+
+运行结果发现,`AnnotationMetadata` 的实现类是 `SimpleAnnotationMetadata`,这是一个基于 ASM 的实现,不依赖标准的 Java 反射机制。
+
+```java
+AnnotationMetadata impl class is class org.springframework.core.type.classreading.SimpleAnnotationMetadata
+MyBean is a @Component: true
+@Component value is myBean
+```
+
+#### JAVA反射技术
+
+使用 Java 反射技术创建 `AnnotationMetadata` 对象,通过调用 `AnnotationMetadata.introspect(MyBean.class)` 方法,加载了名为 `MyBean` 的类的元数据。然后通过 `AnnotationMetadata` 检查是否被 `@Component` 注解标记,并获取注解属性值,最后输出相应的结果。使用标准 Java 反射机制来实现这些功能,这是一种通用的方式,适用于大多数 Spring 应用程序。
+
+```java
+public class AnnotationMetadataDemoByReflection {
+
+ public static void main(String[] args) throws Exception {
+ // 获取 AnnotationMetadata
+ AnnotationMetadata annotationMetadata = AnnotationMetadata.introspect(MyBean.class);
+
+ System.out.println("AnnotationMetadata impl class is " + annotationMetadata.getClass());
+
+ // 检查 MyBean 类是否被 @Component 注解标记
+ boolean isComponent = annotationMetadata.hasAnnotation(Component.class.getName());
+ System.out.println("MyBean is a @Component: " + isComponent);
+
+ // 获取 MyBean 类上的注解属性
+ if (isComponent) {
+ Map annotationAttributes = annotationMetadata.getAnnotationAttributes(Component.class.getName());
+ System.out.println("@Component value is " + annotationAttributes.get("value"));
+ }
+ }
+}
+```
+
+运行结果发现,`AnnotationMetadata` 的实现类是 `StandardAnnotationMetadata`,这是一个基于 JAVA反射机制的实现的。
+
+```java
+AnnotationMetadata impl class is class org.springframework.core.type.StandardAnnotationMetadata
+MyBean is a @Component: true
+@Component value is myBean
+```
+
+### 七、与其他组件的关系
+
+1. **组件扫描**
+ - `AnnotationMetadata` 与 `ClassPathBeanDefinitionScanner` 类相关。在组件扫描过程中,`ClassPathBeanDefinitionScanner` 使用 `AnnotationMetadata` 来检查类上的特定注解(如 `@Component`、`@Service`、`@Controller` 等),并将这些类注册为 Spring Beans。
+2. **Bean 定义**
+ - `AnnotationMetadata` 与 `AnnotatedGenericBeanDefinition`,`ScannedGenericBeanDefinition` 类相关。当 Spring 扫描到带有注解的类时,会使用 `AnnotationMetadata` 来构建 Bean 定义。它提取类上的注解信息,包括 Bean 名称、作用域、依赖关系等,然后将这些信息用于创建 Bean 定义。
+3. **条件化的 Bean 注册**
+ - `AnnotationMetadata` 与条件化 Bean 注册相关的类有 `Conditional` 注解和 `Condition` 接口。在条件化注册中,`AnnotationMetadata` 用于评估 `@Conditional` 注解,根据条件的计算结果来决定是否注册特定的 Bean。
+
+### 八、常见问题
+
+1. **如何获取类上的特定注解信息?**
+ - 使用 `AnnotationMetadata` 的 `getAnnotations()` 方法,然后可以过滤和检查每个注解以获取特定注解的信息。例如,使用 `isDirectlyPresent()` 来检查注解是否直接存在于类上,然后使用 `getAnnotationAttributes()` 获取注解的属性值。
+2. **如何判断类是否被特定注解标记?**
+ - 使用 `AnnotationMetadata` 的 `hasAnnotation()` 方法,提供注解的完全限定名,可以检查类是否被特定注解标记。
+3. **如何处理条件化注册的问题?**
+ - 当使用条件化注解(如 `@Conditional`)时,需要使用 `AnnotationMetadata` 评估条件,并根据条件的结果来决定是否注册 Bean。通常,这需要自定义条件类和实现 `Condition` 接口来处理条件逻辑。
+4. **如何扫描和分析多个类?**
+ - 可以使用 Spring 的组件扫描功能,通过配置 `@ComponentScan` 注解或 XML 配置文件来扫描多个类。然后,`AnnotationMetadata` 可以用于分析扫描到的每个类。
+5. **如何自定义注解处理器?**
+ - 如果需要自定义处理特定注解的逻辑,可以编写自定义注解处理器,并使用 `AnnotationMetadata` 来分析和处理注解信息。这通常涉及实现自定义逻辑,例如动态创建 Bean 定义或执行其他操作。
+6. **如何选择使用 ASM 或标准 Java 反射?**
+ - 当选择使用 `AnnotationMetadata` 时,需要根据具体需求和性能考虑选择使用 ASM 或标准 Java 反射的实现。ASM 更适合需要高性能的场景,而标准 Java 反射通常更易于使用和维护。选择取决于项目的要求和性能需求。
\ No newline at end of file
diff --git a/spring-metadata/spring-metadata-annotationMetadata/pom.xml b/spring-metadata/spring-metadata-annotationMetadata/pom.xml
new file mode 100644
index 0000000..9ebf863
--- /dev/null
+++ b/spring-metadata/spring-metadata-annotationMetadata/pom.xml
@@ -0,0 +1,14 @@
+
+
+
+ spring-metadata
+ com.xcs.spring
+ 0.0.1-SNAPSHOT
+
+
+ 4.0.0
+ spring-metadata-annotationMetadata
+
+
\ No newline at end of file
diff --git a/spring-metadata/spring-metadata-annotationMetadata/src/main/java/com/xcs/spring/AnnotationMetadataDemoByASM.java b/spring-metadata/spring-metadata-annotationMetadata/src/main/java/com/xcs/spring/AnnotationMetadataDemoByASM.java
new file mode 100644
index 0000000..584078c
--- /dev/null
+++ b/spring-metadata/spring-metadata-annotationMetadata/src/main/java/com/xcs/spring/AnnotationMetadataDemoByASM.java
@@ -0,0 +1,39 @@
+package com.xcs.spring;
+
+import com.xcs.spring.bean.MyBean;
+import org.springframework.core.type.AnnotationMetadata;
+import org.springframework.core.type.classreading.MetadataReader;
+import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * @author xcs
+ * @date 2023年10月31日 16时17分
+ **/
+public class AnnotationMetadataDemoByASM {
+
+ public static void main(String[] args) throws Exception {
+ // 创建 MetadataReaderFactory
+ SimpleMetadataReaderFactory readerFactory = new SimpleMetadataReaderFactory();
+ // 获取 MetadataReader
+ MetadataReader metadataReader = readerFactory.getMetadataReader("com.xcs.spring.bean.MyBean");
+
+ // 获取 AnnotationMetadata
+ AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
+
+ System.out.println("AnnotationMetadata impl class is " + annotationMetadata.getClass());
+
+ // 检查 MyBean 类是否被 @Component 注解标记
+ boolean isComponent = annotationMetadata.hasAnnotation(Component.class.getName());
+ System.out.println("MyBean is a @Component: " + isComponent);
+
+ // 获取 MyBean 类上的注解属性
+ if (isComponent) {
+ Map annotationAttributes = annotationMetadata.getAnnotationAttributes(Component.class.getName());
+ System.out.println("@Component value is " + annotationAttributes.get("value"));
+ }
+ }
+}
diff --git a/spring-metadata/spring-metadata-annotationMetadata/src/main/java/com/xcs/spring/AnnotationMetadataDemoByReflection.java b/spring-metadata/spring-metadata-annotationMetadata/src/main/java/com/xcs/spring/AnnotationMetadataDemoByReflection.java
new file mode 100644
index 0000000..9acbcb1
--- /dev/null
+++ b/spring-metadata/spring-metadata-annotationMetadata/src/main/java/com/xcs/spring/AnnotationMetadataDemoByReflection.java
@@ -0,0 +1,31 @@
+package com.xcs.spring;
+
+import com.xcs.spring.bean.MyBean;
+import org.springframework.core.type.AnnotationMetadata;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @author xcs
+ * @date 2023年10月31日 16时17分
+ **/
+public class AnnotationMetadataDemoByReflection {
+
+ public static void main(String[] args) throws Exception {
+ // 获取 AnnotationMetadata
+ AnnotationMetadata annotationMetadata = AnnotationMetadata.introspect(MyBean.class);
+
+ System.out.println("AnnotationMetadata impl class is " + annotationMetadata.getClass());
+
+ // 检查 MyBean 类是否被 @Component 注解标记
+ boolean isComponent = annotationMetadata.hasAnnotation(Component.class.getName());
+ System.out.println("MyBean is a @Component: " + isComponent);
+
+ // 获取 MyBean 类上的注解属性
+ if (isComponent) {
+ Map annotationAttributes = annotationMetadata.getAnnotationAttributes(Component.class.getName());
+ System.out.println("@Component value is " + annotationAttributes.get("value"));
+ }
+ }
+}
diff --git a/spring-metadata/spring-metadata-annotationMetadata/src/main/java/com/xcs/spring/bean/MyBean.java b/spring-metadata/spring-metadata-annotationMetadata/src/main/java/com/xcs/spring/bean/MyBean.java
new file mode 100644
index 0000000..50ae9ba
--- /dev/null
+++ b/spring-metadata/spring-metadata-annotationMetadata/src/main/java/com/xcs/spring/bean/MyBean.java
@@ -0,0 +1,11 @@
+package com.xcs.spring.bean;
+
+import org.springframework.stereotype.Component;
+
+/**
+ * @author xcs
+ * @date 2023年10月31日 16时21分
+ **/
+@Component("myBean")
+public class MyBean {
+}
diff --git a/spring-metadata/spring-metadata-metadataReader/README.md b/spring-metadata/spring-metadata-metadataReader/README.md
index 6eee812..c0014ec 100644
--- a/spring-metadata/spring-metadata-metadataReader/README.md
+++ b/spring-metadata/spring-metadata-metadataReader/README.md
@@ -91,9 +91,6 @@ classDiagram
}
class SimpleMetadataReader {
- -ClassLoader classLoader
- -Set protocolResolvers
- -Map, Map> resourceCaches
}
SimpleMetadataReader ..|> MetadataReader