diff --git a/docs/Spring/clazz/Spring-Metadata.md b/docs/Spring/clazz/Spring-Metadata.md new file mode 100644 index 0000000..a4b1d8e --- /dev/null +++ b/docs/Spring/clazz/Spring-Metadata.md @@ -0,0 +1,997 @@ +# Spring 元信息 + +- Author: [HuiFer](https://github.com/huifer) +- 源码阅读仓库: [SourceHot-Spring](https://github.com/SourceHot/spring-framework-read) + + +## ClassMetadata + + + + +```java +public interface ClassMetadata { + + /** + * 类名 + */ + String getClassName(); + + /** + * 是否是接口 + */ + boolean isInterface(); + + /** + * 是否是注解 + */ + boolean isAnnotation(); + + /** + * 是否是超类 + */ + boolean isAbstract(); + + /** + * 是否允许创建,实例化 + */ + default boolean isConcrete() { + return !(isInterface() || isAbstract()); + } + + /** + * 是否有final修饰 + */ + boolean isFinal(); + + /** + * 是否独立 + */ + boolean isIndependent(); + + /** + * 是否有内部类 + */ + default boolean hasEnclosingClass() { + return (getEnclosingClassName() != null); + } + + /** + * 是否是基础类 + */ + @Nullable + String getEnclosingClassName(); + + /** + * 是否有父类 + */ + default boolean hasSuperClass() { + return (getSuperClassName() != null); + } + + /** + * 父类名称 + */ + @Nullable + String getSuperClassName(); + + /** + * 实现类名称列表 + */ + String[] getInterfaceNames(); + + /** + * 成员列表 + * @since 3.1 + */ + String[] getMemberClassNames(); + +} +``` + + + + + +![image-20200824094154847](/images/spring/image-20200824094154847.png) + + + + + +## AnnotatedTypeMetadata + + + +```java +public interface AnnotatedTypeMetadata { + + /** + * 获取所有注解 + */ + MergedAnnotations getAnnotations(); + + /** + * 是否有注解 + */ + default boolean isAnnotated(String annotationName) { + return getAnnotations().isPresent(annotationName); + } + + /** + * 获取注解的属性 + */ + @Nullable + default Map getAnnotationAttributes(String annotationName) { + return getAnnotationAttributes(annotationName, false); + } + // 省略其他 + +} +``` + + + +## + +## AnnotationMetadata + +```java +public interface AnnotationMetadata extends ClassMetadata, AnnotatedTypeMetadata { + + /** + * 获取注解名称,全类名 + */ + default Set getAnnotationTypes() { + return getAnnotations().stream() + .filter(MergedAnnotation::isDirectlyPresent) + .map(annotation -> annotation.getType().getName()) + .collect(Collectors.toCollection(LinkedHashSet::new)); + } + + /** + * 注解全类名 + */ + default Set 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 getAnnotatedMethods(String annotationName); + + + /** + * 通过反射创建一个注解的元信息 + */ + static AnnotationMetadata introspect(Class type) { + return StandardAnnotationMetadata.from(type); + } + +} +``` + + + + + + + +## MethodMetadata + +```java +public interface MethodMetadata extends AnnotatedTypeMetadata { + + /** + * 方法名称 + */ + String getMethodName(); + + /** + * 方法全路径 + */ + String getDeclaringClassName(); + + /** + * 返回值类型 + */ + String getReturnTypeName(); + + /** + * 是不是abstrac修饰 + */ + boolean isAbstract(); + + /** + * 是否 static 修饰 + */ + boolean isStatic(); + + /** + * 是否 final 修饰 + */ + boolean isFinal(); + + /** + * 是否重载 + */ + boolean isOverridable(); + +} +``` + + + + + + + +## MetadataReader + +```java +public interface MetadataReader { + + /** + * Return the resource reference for the class file. + * + * 获取资源 + */ + Resource getResource(); + + /** + * Read basic class metadata for the underlying class. + * 获取类的元信息 + */ + ClassMetadata getClassMetadata(); + + /** + * Read full annotation metadata for the underlying class, + * including metadata for annotated methods. + * + * 获取注解的元信息 + */ + AnnotationMetadata getAnnotationMetadata(); + +} +``` + + + + + +## MetadataReaderFactory + +- 用来创建 MetadataReader + +```java +public interface MetadataReaderFactory { + + /** + * Obtain a MetadataReader for the given class name. + * @param className the class name (to be resolved to a ".class" file) + * @return a holder for the ClassReader instance (never {@code null}) + * @throws IOException in case of I/O failure + */ + MetadataReader getMetadataReader(String className) throws IOException; + + /** + * Obtain a MetadataReader for the given resource. + * @param resource the resource (pointing to a ".class" file) + * @return a holder for the ClassReader instance (never {@code null}) + * @throws IOException in case of I/O failure + */ + MetadataReader getMetadataReader(Resource resource) throws IOException; + +} +``` + + + +- 接口解释的差不多了.接下来看一些实现 + + + + + +## StandardClassMetadata + +- 通过JAVA 反射来获取类的元信息 + +- 这个类采用的方式是Java class的方法,通过构造方法来填写一个Class对象. 之后使用这个对象的方法 + + + + + +```java +public class StandardClassMetadata implements ClassMetadata { + + private final Class introspectedClass; + + @Deprecated + public StandardClassMetadata(Class introspectedClass) { + Assert.notNull(introspectedClass, "Class must not be null"); + this.introspectedClass = introspectedClass; + } + + /** + * Return the underlying Class. + */ + public final Class getIntrospectedClass() { + return this.introspectedClass; + } + + + @Override + public String getClassName() { + return this.introspectedClass.getName(); + } + + @Override + public boolean isInterface() { + return this.introspectedClass.isInterface(); + } + + @Override + public boolean isAnnotation() { + return this.introspectedClass.isAnnotation(); + } + + @Override + public boolean isAbstract() { + return Modifier.isAbstract(this.introspectedClass.getModifiers()); + } + + @Override + public boolean isFinal() { + return Modifier.isFinal(this.introspectedClass.getModifiers()); + } + + @Override + public boolean isIndependent() { + return (!hasEnclosingClass() || + (this.introspectedClass.getDeclaringClass() != null && + Modifier.isStatic(this.introspectedClass.getModifiers()))); + } + + @Override + @Nullable + public String getEnclosingClassName() { + Class enclosingClass = this.introspectedClass.getEnclosingClass(); + return (enclosingClass != null ? enclosingClass.getName() : null); + } + + @Override + @Nullable + public String getSuperClassName() { + Class superClass = this.introspectedClass.getSuperclass(); + return (superClass != null ? superClass.getName() : null); + } + + @Override + public String[] getInterfaceNames() { + Class[] ifcs = this.introspectedClass.getInterfaces(); + String[] ifcNames = new String[ifcs.length]; + for (int i = 0; i < ifcs.length; i++) { + ifcNames[i] = ifcs[i].getName(); + } + return ifcNames; + } + + @Override + public String[] getMemberClassNames() { + LinkedHashSet memberClassNames = new LinkedHashSet<>(4); + for (Class nestedClass : this.introspectedClass.getDeclaredClasses()) { + memberClassNames.add(nestedClass.getName()); + } + return StringUtils.toStringArray(memberClassNames); + } + +} +``` + + + + + +## StandardMethodMetadata + +- 通过java反射获取方法的元信息 +- 构造方法传递一个method + - 如果这个方法有注解,会进行注解的解析 + + + +```java +public class StandardMethodMetadata implements MethodMetadata { + + private final Method introspectedMethod; + + private final boolean nestedAnnotationsAsMap; + + private final MergedAnnotations mergedAnnotations; + + @Deprecated + public StandardMethodMetadata(Method introspectedMethod) { + this(introspectedMethod, false); + } + + + @Deprecated + public StandardMethodMetadata(Method introspectedMethod, boolean nestedAnnotationsAsMap) { + Assert.notNull(introspectedMethod, "Method must not be null"); + this.introspectedMethod = introspectedMethod; + this.nestedAnnotationsAsMap = nestedAnnotationsAsMap; + this.mergedAnnotations = MergedAnnotations.from( + introspectedMethod, SearchStrategy.DIRECT, RepeatableContainers.none()); + } + + + @Override + public MergedAnnotations getAnnotations() { + return this.mergedAnnotations; + } + + /** + * Return the underlying Method. + */ + public final Method getIntrospectedMethod() { + return this.introspectedMethod; + } + + @Override + public String getMethodName() { + return this.introspectedMethod.getName(); + } + + @Override + public String getDeclaringClassName() { + return this.introspectedMethod.getDeclaringClass().getName(); + } + + @Override + public String getReturnTypeName() { + return this.introspectedMethod.getReturnType().getName(); + } + + @Override + public boolean isAbstract() { + return Modifier.isAbstract(this.introspectedMethod.getModifiers()); + } + + @Override + public boolean isStatic() { + return Modifier.isStatic(this.introspectedMethod.getModifiers()); + } + + @Override + public boolean isFinal() { + return Modifier.isFinal(this.introspectedMethod.getModifiers()); + } + + @Override + public boolean isOverridable() { + return !isStatic() && !isFinal() && !isPrivate(); + } + + private boolean isPrivate() { + return Modifier.isPrivate(this.introspectedMethod.getModifiers()); + } + + @Override + @Nullable + public Map getAnnotationAttributes(String annotationName, boolean classValuesAsString) { + if (this.nestedAnnotationsAsMap) { + return MethodMetadata.super.getAnnotationAttributes(annotationName, classValuesAsString); + } + return AnnotatedElementUtils.getMergedAnnotationAttributes(this.introspectedMethod, + annotationName, classValuesAsString, false); + } + + /** + * 获取所有注解的信息 + */ + @Override + @Nullable + public MultiValueMap getAllAnnotationAttributes(String annotationName, boolean classValuesAsString) { + if (this.nestedAnnotationsAsMap) { + return MethodMetadata.super.getAllAnnotationAttributes(annotationName, classValuesAsString); + } + return AnnotatedElementUtils.getAllAnnotationAttributes(this.introspectedMethod, + annotationName, classValuesAsString, false); + } + +} +``` + + + +## StandardAnnotationMetadata + +- StandardAnnotationMetadata是StandardClassMetadata的子类 + +- 还是一个基于JAVA 反射做的一个类 + + + +- 获取注解属性map + +```java +@Override +@Nullable +public Map getAnnotationAttributes(String annotationName, boolean classValuesAsString) { + if (this.nestedAnnotationsAsMap) { + return AnnotationMetadata.super.getAnnotationAttributes(annotationName, classValuesAsString); + } + return AnnotatedElementUtils.getMergedAnnotationAttributes( + getIntrospectedClass(), annotationName, classValuesAsString, false); +} +``` + +- `org.springframework.core.annotation.AnnotatedElementUtils#getMergedAnnotationAttributes(java.lang.reflect.AnnotatedElement, java.lang.String, boolean, boolean)` + - `org.springframework.core.annotation.AnnotatedElementUtils#getAnnotationAttributes` + - `org.springframework.core.annotation.MergedAnnotation#asAnnotationAttributes` + + + +```java +@Nullable +public static AnnotationAttributes getMergedAnnotationAttributes(AnnotatedElement element, + String annotationName, boolean classValuesAsString, boolean nestedAnnotationsAsMap) { + + MergedAnnotation mergedAnnotation = getAnnotations(element) + .get(annotationName, null, MergedAnnotationSelectors.firstDirectlyDeclared()); + return getAnnotationAttributes(mergedAnnotation, classValuesAsString, nestedAnnotationsAsMap); +} +``` + + + +- 查看这个方法的源码借助测试类`org.springframework.core.annotation.AnnotatedElementUtilsTests#getMergedAnnotationAttributesOnClassWithLocalAnnotation` +- getAnnotations() 方法 + + + + + +### getAnnotations + +- `org.springframework.core.annotation.MergedAnnotations#from(java.lang.reflect.AnnotatedElement, org.springframework.core.annotation.MergedAnnotations.SearchStrategy, org.springframework.core.annotation.RepeatableContainers)` + - `org.springframework.core.annotation.TypeMappedAnnotations#from(java.lang.reflect.AnnotatedElement, org.springframework.core.annotation.MergedAnnotations.SearchStrategy, org.springframework.core.annotation.RepeatableContainers, org.springframework.core.annotation.AnnotationFilter)` + + + +- 最终我们找到的代码如下 + +```java +static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy, + RepeatableContainers repeatableContainers, AnnotationFilter annotationFilter) { + + if (AnnotationsScanner.isKnownEmpty(element, searchStrategy)) { + return NONE; + } + return new TypeMappedAnnotations(element, searchStrategy, repeatableContainers, annotationFilter); +} +``` + + + +- 判断是否为空. 为空返回None,不会为空构造出一个对象org.springframework.core.annotation.TypeMappedAnnotations + + + + + +### MergedAnnotations + + + + + +```java +public interface MergedAnnotations extends Iterable> { + + //确定注解是否存在 + boolean isPresent(Class annotationType); + //注解是否直接存在 + boolean isDirectlyPresent(Class annotationType); + // 获取匹配的注解 + MergedAnnotation get(Class annotationType); + // 省略其他 + +} +``` + +- 这个接口中还有两个方法 + + 1. `of` + 将多个`MergedAnnotations`合并 + + 2. `from` + + 将多个注解合并 + + + + + + + +### SearchStrategy + +```java +enum SearchStrategy { + + /** + * Find only directly declared annotations, without considering + * {@link Inherited @Inherited} annotations and without searching + * superclasses or implemented interfaces. + * + * 直接查找 + */ + DIRECT, + + /** + * Find all directly declared annotations as well as any + * {@link Inherited @Inherited} superclass annotations. This strategy + * is only really useful when used with {@link Class} types since the + * {@link Inherited @Inherited} annotation is ignored for all other + * {@linkplain AnnotatedElement annotated elements}. This strategy does + * not search implemented interfaces. + * + * 继承查找 + */ + INHERITED_ANNOTATIONS, + + /** + * Find all directly declared and superclass annotations. This strategy + * is similar to {@link #INHERITED_ANNOTATIONS} except the annotations + * do not need to be meta-annotated with {@link Inherited @Inherited}. + * This strategy does not search implemented interfaces. + * 查找当前类和父类的注解 + */ + SUPERCLASS, + + /** + * Perform a full search of the entire type hierarchy, including + * superclasses and implemented interfaces. Superclass annotations do + * not need to be meta-annotated with {@link Inherited @Inherited}. + */ + TYPE_HIERARCHY, + + /** + * Perform a full search of the entire type hierarchy on the source + * and any enclosing classes. This strategy is similar to + * {@link #TYPE_HIERARCHY} except that {@linkplain Class#getEnclosingClass() + * enclosing classes} are also searched. Superclass annotations do not + * need to be meta-annotated with {@link Inherited @Inherited}. When + * searching a {@link Method} source, this strategy is identical to + * {@link #TYPE_HIERARCHY}. + */ + TYPE_HIERARCHY_AND_ENCLOSING_CLASSES +} +``` + + + + + +- `org.springframework.core.annotation.TypeMappedAnnotations#get(java.lang.String, java.util.function.Predicate>, org.springframework.core.annotation.MergedAnnotationSelector)` + +```java +@Override +public MergedAnnotation get(String annotationType, + @Nullable Predicate> predicate, + @Nullable MergedAnnotationSelector selector) { + // 匹配校验 + if (this.annotationFilter.matches(annotationType)) { + return MergedAnnotation.missing(); + } + MergedAnnotation result = scan(annotationType, + new MergedAnnotationFinder<>(annotationType, predicate, selector)); + return (result != null ? result : MergedAnnotation.missing()); +} +``` + + + + + +#### Scan + +`org.springframework.core.annotation.AnnotationsScanner#scan(C, java.lang.reflect.AnnotatedElement, org.springframework.core.annotation.MergedAnnotations.SearchStrategy, org.springframework.core.annotation.AnnotationsProcessor, java.util.function.BiPredicate>)` + +```java +@Nullable +static R scan(C context, AnnotatedElement source, SearchStrategy searchStrategy, + AnnotationsProcessor processor, @Nullable BiPredicate> classFilter) { + + R result = process(context, source, searchStrategy, processor, classFilter); + return processor.finish(result); +} +``` + + + +在这个里面重点关注`PROCESS`方法 + +```java +@Nullable +private static R process(C context, AnnotatedElement source, + SearchStrategy searchStrategy, AnnotationsProcessor processor, + @Nullable BiPredicate> classFilter) { + + if (source instanceof Class) { + return processClass(context, (Class) source, searchStrategy, processor, classFilter); + } + if (source instanceof Method) { + return processMethod(context, (Method) source, searchStrategy, processor, classFilter); + } + return processElement(context, source, processor, classFilter); +} +``` + + + +测试类 + +```java + @Transactional("TxConfig") + static class TxConfig { + } +``` + +显然这是一个类他会走`processClass`方法 + + + +- 根据扫描方式进行扫描 + +```java +@Nullable +private static R processClass(C context, Class source, + SearchStrategy searchStrategy, AnnotationsProcessor processor, + @Nullable BiPredicate> classFilter) { + + switch (searchStrategy) { + case DIRECT: + return processElement(context, source, processor, classFilter); + case INHERITED_ANNOTATIONS: + return processClassInheritedAnnotations(context, source, searchStrategy, processor, classFilter); + case SUPERCLASS: + return processClassHierarchy(context, source, processor, classFilter, false, false); + case TYPE_HIERARCHY: + return processClassHierarchy(context, source, processor, classFilter, true, false); + case TYPE_HIERARCHY_AND_ENCLOSING_CLASSES: + return processClassHierarchy(context, source, processor, classFilter, true, true); + } + throw new IllegalStateException("Unsupported search strategy " + searchStrategy); +} +``` + + + +- 扫描的形式就不贴出完整代码了 + + + +`finish`就包装一下返回. + +- 此时`org.springframework.core.annotation.AnnotatedElementUtils#getMergedAnnotationAttributes(java.lang.reflect.AnnotatedElement, java.lang.String, boolean, boolean)`这个方法走到了最后一步`org.springframework.core.annotation.AnnotatedElementUtils#getAnnotationAttributes` + + + + + +- 最后的组装map方法 + + `org.springframework.core.annotation.TypeMappedAnnotation#asMap(java.util.function.Function,T>, org.springframework.core.annotation.MergedAnnotation.Adapt...)` + + + + + +```java +@Override +public AnnotationAttributes asAnnotationAttributes(Adapt... adaptations) { + return asMap(mergedAnnotation -> new AnnotationAttributes(mergedAnnotation.getType()), adaptations); +} +``` + + + +```java +@Override +public > T asMap(Function, T> factory, Adapt... adaptations) { + T map = factory.apply(this); + Assert.state(map != null, "Factory used to create MergedAnnotation Map must not return null"); + AttributeMethods attributes = this.mapping.getAttributes(); + for (int i = 0; i < attributes.size(); i++) { + Method attribute = attributes.get(i); + Object value = (isFiltered(attribute.getName()) ? null : + getValue(i, getTypeForMapOptions(attribute, adaptations))); + if (value != null) { + map.put(attribute.getName(), + adaptValueForMapOptions(attribute, value, map.getClass(), factory, adaptations)); + } + } + return map; +} +``` + +- 获取属性列表,循环, 放入map 返回. + + map + + ​ key: 注解的函数 + + ​ value: 函数对应的值 + + + +```java +@Transactional("TxConfig") +``` + +```java +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.METHOD}) +@Inherited +@interface Transactional { + + String value() default ""; + + String qualifier() default "transactionManager"; + + boolean readOnly() default false; +} +``` + +如果是上面这样的结构那么返回值为 + +```json +value:TxConfig +qulifiter:transactionManager +readOnlay:false +``` + +![image-20200824104529315](/images/spring/image-20200824104529315.png) + + + + + + + + + + + +## SimpleMetadataReader + +- 构造方法传递三个参数直接使用 + + ```java + final class SimpleMetadataReader implements MetadataReader { + + private static final int PARSING_OPTIONS = ClassReader.SKIP_DEBUG + | ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES; + + private final Resource resource; + + private final AnnotationMetadata annotationMetadata; + + + SimpleMetadataReader(Resource resource, @Nullable ClassLoader classLoader) throws IOException { + SimpleAnnotationMetadataReadingVisitor visitor = new SimpleAnnotationMetadataReadingVisitor(classLoader); + getClassReader(resource).accept(visitor, PARSING_OPTIONS); + this.resource = resource; + this.annotationMetadata = visitor.getMetadata(); + } + + private static ClassReader getClassReader(Resource resource) throws IOException { + try (InputStream is = new BufferedInputStream(resource.getInputStream())) { + try { + return new ClassReader(is); + } + catch (IllegalArgumentException ex) { + throw new NestedIOException("ASM ClassReader failed to parse class file - " + + "probably due to a new Java class file version that isn't supported yet: " + resource, ex); + } + } + } + + + @Override + public Resource getResource() { + return this.resource; + } + + @Override + public ClassMetadata getClassMetadata() { + return this.annotationMetadata; + } + + @Override + public AnnotationMetadata getAnnotationMetadata() { + return this.annotationMetadata; + } + + } + ``` + + + + + + + +## SimpleMetadataReaderFactory + +- 关注点为如何获取`MetadataReader` + 1. 通过资源直接new出来 + 2. 通过className转换成资源地址, + 3. 将资源地址转换成`Resource`对象 + 4. new出来 + +```java +@Override +public MetadataReader getMetadataReader(String className) throws IOException { + try { + String resourcePath = ResourceLoader.CLASSPATH_URL_PREFIX + + ClassUtils.convertClassNameToResourcePath(className) + ClassUtils.CLASS_FILE_SUFFIX; + Resource resource = this.resourceLoader.getResource(resourcePath); + return getMetadataReader(resource); + } + catch (FileNotFoundException ex) { + // Maybe an inner class name using the dot name syntax? Need to use the dollar syntax here... + // ClassUtils.forName has an equivalent check for resolution into Class references later on. + int lastDotIndex = className.lastIndexOf('.'); + if (lastDotIndex != -1) { + String innerClassName = + className.substring(0, lastDotIndex) + '$' + className.substring(lastDotIndex + 1); + String innerClassResourcePath = ResourceLoader.CLASSPATH_URL_PREFIX + + ClassUtils.convertClassNameToResourcePath(innerClassName) + ClassUtils.CLASS_FILE_SUFFIX; + Resource innerClassResource = this.resourceLoader.getResource(innerClassResourcePath); + if (innerClassResource.exists()) { + return getMetadataReader(innerClassResource); + } + } + throw ex; + } +} + +@Override +public MetadataReader getMetadataReader(Resource resource) throws IOException { + return new SimpleMetadataReader(resource, this.resourceLoader.getClassLoader()); +} +``` \ No newline at end of file diff --git a/images/spring/image-20200824094154847.png b/images/spring/image-20200824094154847.png new file mode 100644 index 0000000..7599784 Binary files /dev/null and b/images/spring/image-20200824094154847.png differ diff --git a/images/spring/image-20200824104529315.png b/images/spring/image-20200824104529315.png new file mode 100644 index 0000000..197b8d2 Binary files /dev/null and b/images/spring/image-20200824104529315.png differ