Spring元數據Metadata的使用,注解編程之AnnotationMetadata,ClassMetadata、MetadataReaderFactory【享學Spring】


每篇一句
不要擔心你此次此刻的付出得不到回報,因為你現在的付出是為了扎根

前言
Spring在2.0的時候就支持了基於XML Schema的擴展機制,讓我們可以自定義的對xml配置文件進行擴展(四大步驟,有興趣的可以自己學習),比如鼎鼎大名的Dubbo它就擴展了xml,用它來引入服務或者導出服務。
隨着Spring3.0+的發展,xml慢慢的淡出了我們的視野,特別是Spring Boot的流行讓xml徹底消失,所有的xml配置都使用注解的方式進行了代替。有的人說注解編程源碼難度是 XML 擴展好幾倍,其實我並不這么認為,本文就着眼於大多數小伙伴比較費解的元數據(Metadata)進行分析,給深入理解注解編程鋪路。

元數據
元數據:數據的數據。比如Class就是一種元數據。Metadata在org.springframework.core.type包名下,還有用於讀取的子包classreading也是重要知識點。此體系大致的類結構列出如下圖:

 

可以看到頂層接口有兩個:ClassMetadata和AnnotatedTypeMetadata

注解上的注解,Spring將其定義為元注解(meta-annotation),如 @Component標注在 @Service上,@Component就被稱作為元注解。后面我們就將注解的注解稱為元注解。

ClassMetadata:對Class的抽象和適配
此接口的所有方法,基本上都跟Class有關。

// @since 2.5
public interface ClassMetadata {

// 返回類名(注意返回的是最原始的那個className)
String getClassName();
boolean isInterface();
// 是否是注解
boolean isAnnotation();
boolean isAbstract();
// 是否允許創建 不是接口且不是抽象類 這里就返回true了
boolean isConcrete();
boolean isFinal();
// 是否是獨立的(能夠創建對象的) 比如是Class、或者內部類、靜態內部類
boolean isIndependent();
// 是否有內部類之類的東東
boolean hasEnclosingClass();
@Nullable
String getEnclosingClassName();
boolean hasSuperClass();
@Nullable
String getSuperClassName();
// 會把實現的所有接口名稱都返回 具體依賴於Class#getSuperclass
String[] getInterfaceNames();

// 基於:Class#getDeclaredClasses 返回類中定義的公共、私有、保護的內部類
String[] getMemberClassNames();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
它的繼承樹如下:


StandardClassMetadata
基於Java標准的(Standard)反射實現元數據的獲取。

// @since 2.5
public class StandardClassMetadata implements ClassMetadata {
// 用於內省的Class類
private final Class<?> introspectedClass;

// 唯一構造函數:傳進來的Class,作為內部的內省對象
public StandardClassMetadata(Class<?> introspectedClass) {
Assert.notNull(introspectedClass, "Class must not be null");
this.introspectedClass = introspectedClass;
}
... // 后面所有的方法實現,都是基於introspectedClass,類似代理模式。舉例如下:

public final Class<?> getIntrospectedClass() {
return this.introspectedClass;
}
@Override
public boolean isInterface() {
return this.introspectedClass.isInterface();
}
@Override
public String[] getMemberClassNames() {
LinkedHashSet<String> memberClassNames = new LinkedHashSet<>(4);
for (Class<?> nestedClass : this.introspectedClass.getDeclaredClasses()) {
memberClassNames.add(nestedClass.getName());
}
return StringUtils.toStringArray(memberClassNames);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
它有個非常重要的子類:StandardAnnotationMetadata它和注解密切相關,在文章下半部分重點分析。

MethodsMetadata:新增訪問方法元數據的接口
它是子接口,主要增加了從Class里獲取到MethodMetadata們的方法:

// @since 2.1 可以看到它出現得更早一些
public interface MethodsMetadata extends ClassMetadata {
// 返回該class所有的方法
Set<MethodMetadata> getMethods();
// 方法指定方法名的方法們(因為有重載嘛~)
Set<MethodMetadata> getMethods(String name);
}
1
2
3
4
5
6
7
名字上請不要和MethodMetadata搞混了,MethodMetadata是AnnotatedTypeMetadata的子接口,代表具體某一個Type(方法上的注解);而此類是個ClassMetadata,它能獲取到本類里所有的方法Method(MethodMetadata)~

AnnotatedTypeMetadata:對注解元素的封裝適配
什么叫注解元素(AnnotatedElement)?比如我們常見的Class、Method、Constructor、Parameter等等都屬於它的子類都屬於注解元素。簡單理解:只要能在上面標注注解都屬於這種元素。Spring4.0新增的這個接口提供了對注解統一的、便捷的訪問,使用起來更加的方便高效了。

// @since 4.0
public interface AnnotatedTypeMetadata {

// 此元素是否標注有此注解~~~~
// annotationName:注解全類名
boolean isAnnotated(String annotationName);

// 這個就厲害了:取得指定類型注解的所有的屬性 - 值(k-v)
// annotationName:注解全類名
// classValuesAsString:若是true表示 Class用它的字符串的全類名來表示。這樣可以避免Class被提前加載
@Nullable
Map<String, Object> getAnnotationAttributes(String annotationName);
@Nullable
Map<String, Object> getAnnotationAttributes(String annotationName, boolean classValuesAsString);

// 參見這個方法的含義:AnnotatedElementUtils.getAllAnnotationAttributes
@Nullable
MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName);
@Nullable
MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName, boolean classValuesAsString);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
它的繼承樹如下:

兩個子接口相應的都提供了標准實現以及基於ASM的Visitor模式實現。

ASM 是一個通用的 Java 字節碼操作和分析框架。它可以用於修改現有類或直接以二進制形式動態生成類。 ASM 雖然提供與其他 Java 字節碼框架如 Javassist,CGLIB類似的功能,但是其設計與實現小而快,且性能足夠高。

Spring 直接將 ASM 框架核心源碼內嵌於 Spring-core中,目前`Spring 5.1使用ASM 7 版本。

MethodMetadata:方法描述
子接口,用來描述java.lang.reflect.Method。

// @since 3.0
public interface MethodMetadata extends AnnotatedTypeMetadata {
String getMethodName();
String getDeclaringClassName();
String getReturnTypeName();
boolean isAbstract();
boolean isStatic();
boolean isFinal();
boolean isOverridable();
}
1
2
3
4
5
6
7
8
9
10
StandardMethodMetadata
基於反射的標准實現,略

MethodMetadataReadingVisitor
基於ASM的實現的,繼承自ASM``的org.springframework.asm.MethodVisitor采用Visitor的方式讀取到元數據。

// @since 3.0
public class MethodMetadataReadingVisitor extends MethodVisitor implements MethodMetadata {
...
}
1
2
3
4
AnnotationMetadata(重要)
這是理解Spring注解編程的必備知識,它是ClassMetadata和AnnotatedTypeMetadata的子接口,具有兩者共同能力,並且新增了訪問注解的相關方法。可以簡單理解為它是對注解的抽象。

經常這么使用得到注解里面所有的屬性值:
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(annoMetadata, annType);

// @since 2.5
public interface AnnotationMetadata extends ClassMetadata, AnnotatedTypeMetadata {

//拿到當前類上所有的注解的全類名(注意是全類名)
Set<String> getAnnotationTypes();
// 拿到指定的注解類型
//annotationName:注解類型的全類名
Set<String> getMetaAnnotationTypes(String annotationName);

// 是否包含指定注解 (annotationName:全類名)
boolean hasAnnotation(String annotationName);
//這個厲害了,用於判斷注解類型自己是否被某個元注解類型所標注
//依賴於AnnotatedElementUtils#hasMetaAnnotationTypes
boolean hasMetaAnnotation(String metaAnnotationName);

// 類里面只有有一個方法標注有指定注解,就返回true
//getDeclaredMethods獲得所有方法, AnnotatedElementUtils.isAnnotated是否標注有指定注解
boolean hasAnnotatedMethods(String annotationName);
// 返回所有的標注有指定注解的方法元信息。注意返回的是MethodMetadata 原理基本同上
Set<MethodMetadata> getAnnotatedMethods(String annotationName);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
同樣的它提供了兩種實現方式。

StandardAnnotationMetadata
繼承了StandardClassMetadata,很明顯關於ClassMetadata的實現部分就交給此父類了,自己只關注於AnnotationMetadata接口的實現。

// @since 2.5
public class StandardAnnotationMetadata extends StandardClassMetadata implements AnnotationMetadata {

// 很顯然它是基於標准反射類型:java.lang.annotation.Annotation
// this.annotations = introspectedClass.getAnnotations()
private final Annotation[] annotations;
private final boolean nestedAnnotationsAsMap;
...


// 獲取本Class類上的注解的元注解們
@Override
public Set<String> getMetaAnnotationTypes(String annotationName) {
return (this.annotations.length > 0 ?
AnnotatedElementUtils.getMetaAnnotationTypes(getIntrospectedClass(), annotationName) : Collections.emptySet());
}

@Override
public boolean hasAnnotation(String annotationName) {
for (Annotation ann : this.annotations) {
if (ann.annotationType().getName().equals(annotationName)) {
return true;
}
}
return false;
}
...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
AnnotationMetadataReadingVisitor
繼承自ClassMetadataReadingVisitor,同樣的ClassMetadata部分實現交給了它。

說明:ClassMetadataReadingVisitor是org.springframework.core.type.classreading包下的類,同包的還有我下面重點講述的MetadataReader。此實現類最終委托給AnnotationMetadataReadingVisitor來做的,而它便是ClassMetadataReadingVisitor的子類(MetadataReader的底層實現就是它,使用的ASM的ClassVisitor模式讀取元數據)。

// @since 2.5
public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor implements AnnotationMetadata {
...
}
1
2
3
4
MetadataReader接口
你是否有疑問:為何Spring要提供一個標准實現和一個ASM的實現呢?這里就能給你答案。
此接口是一個訪問ClassMetadata等的簡單門面,實現是委托給org.springframework.asm.ClassReader、ClassVisitor來處理的,它不用把Class加載進JVM就可以拿到元數據,因為它讀取的是資源:Resource,這是它最大的優勢所在。

// @since 2.5
public interface MetadataReader {
// 返回此Class文件的來源(資源)
Resource getResource();
// 返回此Class的元數據信息
ClassMetadata getClassMetadata();
// 返回此類的注解元信息(包括方法的)
AnnotationMetadata getAnnotationMetadata();
}
1
2
3
4
5
6
7
8
9
它的繼承樹如下:


SimpleMetadataReader
它是基於ASM的org.springframework.asm.ClassReader的簡單實現。請注意:此類是非public的,而是default包訪問權限。

final class SimpleMetadataReader implements MetadataReader {
private final Resource resource;
private final ClassMetadata classMetadata;
private final AnnotationMetadata annotationMetadata;

// 唯一構造函數:給上面三個私有屬性賦值,下面就只需提供get方法即可
SimpleMetadataReader(Resource resource, @Nullable ClassLoader classLoader) throws IOException {
InputStream is = new BufferedInputStream(resource.getInputStream());
ClassReader classReader;
try {
classReader = 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);
} finally {
is.close();
}

//通過流構建出一個AnnotationMetadataReadingVisitor,咀咒讀取從而獲取到各種信息
// 它實現了ClassVisitor,所以可以作為入參傳給ClassReader ASM去解析
AnnotationMetadataReadingVisitor visitor = new AnnotationMetadataReadingVisitor(classLoader);
classReader.accept(visitor, ClassReader.SKIP_DEBUG);

this.annotationMetadata = visitor;
// (since AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor)
this.classMetadata = visitor;
this.resource = resource;
}
... // 省略三個get方法
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
MethodsMetadataReader
子接口,新增接口方法:獲取到本類所有的方法元數據們。

public interface MethodsMetadataReader extends MetadataReader {
MethodsMetadata getMethodsMetadata();
...
}
1
2
3
4
它所有的實現都是委托給靜態內部類MethodsMetadataReadingVisitor去做的,它繼承自上面的AnnotationMetadataReadingVisitor並且實現了接口MethodsMetadata的相關方法。

它的唯一實現類DefaultMethodsMetadataReader的訪問權限也是包級別非public,略。

MetadataReaderFactory
MetadataReader的實現都並未public暴露出來,所以我們若想得到它的實例,就只能通過此工廠。

// @since 2.5
public interface MetadataReaderFactory {
//className: the class name (to be resolved to a ".class" file)
MetadataReader getMetadataReader(String className) throws IOException;
MetadataReader getMetadataReader(Resource resource) throws IOException;
}
1
2
3
4
5
6
繼承樹如下:


SimpleMetadataReaderFactory
利用ResourceLoader的簡單實現,加載進資源后,new SimpleMetadataReader(resource)交給此實例分析即可。

public class SimpleMetadataReaderFactory implements MetadataReaderFactory {
// ResourceLoader這個資源加載類應該不陌生了吧
// 默認使用的是DefaultResourceLoader,當然你可以通過構造器指定
private final ResourceLoader resourceLoader;

// 根據類名找到一個Resource
@Override
public MetadataReader getMetadataReader(String className) throws IOException {
try {
// 把..形式換成//.class形式。使用前綴是:classpath: 在類路徑里找哦
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.
... // 此處是兼容內部類形式,代碼略
}
}

// 默認使用的是SimpleMetadataReader哦~~~
@Override
public MetadataReader getMetadataReader(Resource resource) throws IOException {
return new SimpleMetadataReader(resource, this.resourceLoader.getClassLoader());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
此工廠生產的是SimpleMetadataReader。

CachingMetadataReaderFactory
它繼承自SimpleMetadataReaderFactory,沒有其它特殊的,就是提供了緩存能力private Map<Resource, MetadataReader> metadataReaderCache,提高訪問效率。
因為有了它,所以SimpleMetadataReaderFactory就不需要被直接使用了,用它代替。Spring內自然也使用的便是效率更高的它嘍~

MethodsMetadataReaderFactory
它繼承自SimpleMetadataReaderFactory,唯一區別是它生產的是一個MethodsMetadataReader(DefaultMethodsMetadataReader),從而具有了讀取MethodsMetadata的能力。
此類可認為從沒有被Spring內部使用過,暫且可忽略(spring-data工程有用)

Factory工廠的實現都是非常簡單的,畢竟只是為了生產一個實例而已。

Spring注解編程中AnnotationMetadata的使用
Spring從3.0開始就大量的使用到了注解編程模式,所以可想而知它對元數據(特別是注解元數據)的使用是非常多的,此處我只給出非常簡單的總結。

對於MetadataReaderFactory的應用主要體現在幾個地方:

ConfigurationClassPostProcessor:該屬性值最終會傳給ConfigurationClassParser,用於@EnableXXX / @Import等注解的解析上~
// 私有成員變量,默認使用的CachingMetadataReaderFactory
private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory();
1
2
ClassPathScanningCandidateComponentProvider:它用於@ComponentScan的時候解析,拿到元數據判斷是否是@Component的派生注解
public final MetadataReaderFactory getMetadataReaderFactory() {
if (this.metadataReaderFactory == null) {
this.metadataReaderFactory = new CachingMetadataReaderFactory();
}
return this.metadataReaderFactory;
}
1
2
3
4
5
6
Mybatis的SqlSessionFactoryBean:它在使用上非常簡單,只是為了從Resouece里拿到ClassName而已。classMetadata.getClassName()
private static final MetadataReaderFactory METADATA_READER_FACTORY = new CachingMetadataReaderFactory();

private Set<Class<?>> scanClasses(String packagePatterns, Class<?> assignableType) {
...
ClassMetadata classMetadata = METADATA_READER_FACTORY.getMetadataReader(resource).getClassMetadata();
Class<?> clazz = Resources.classForName(classMetadata.getClassName());
...
}
1
2
3
4
5
6
7
8
SourceClass:它是對source對象一個輕量級的包裝,持有AnnotationMetadata 元數據,如下一般實際為一個StandardAnnotationMetadata,比如@EnableTransactionManagement用的就是它
private class SourceClass implements Ordered {
private final Object source; // Class or MetadataReader
private final AnnotationMetadata metadata;
public SourceClass(Object source) {
this.source = source;
if (source instanceof Class) {
this.metadata = new StandardAnnotationMetadata((Class<?>) source, true);
} else {
this.metadata = ((MetadataReader) source).getAnnotationMetadata();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
說明:Spring的@EnableXXX模塊注解很多都使用到了ImportSelector這個接口,此接口的回調方法參數第一個便是AnnotationMetadata代表着@Import所在類的注解的一些元數據們。通常我們會這樣使用它:

// 1、轉換成AnnotationAttributes(LinkedHashMap),模糊掉注解類型(常用)
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);

// 2、拿到指定類型注解的元數據信息(也較為常用)
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true))

// 3、直接使用MetaData
MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes(EnableConfigurationProperties.class.getName(), false);
1
2
3
4
5
6
7
8
使用示例
僅通過文字的說明,我相信很多小伙伴還雲里霧里。正所謂任何文字上的理解都比不上自己動手一試,書是別人的,動手后才是自己的。因此,此處我貼出使用示例代碼,方便你做理解參考:

// 准備一個Class類 作為Demo演示
@Repository("repositoryName")
@Service("serviceName")
@EnableAsync
class MetaDemo extends HashMap<String, String> implements Serializable {
private static class InnerClass {
}

@Autowired
private String getName() {
return "demo";
}
}


public static void main(String[] args) {
StandardAnnotationMetadata metadata = new StandardAnnotationMetadata(MetaDemo.class, true);

// 演示ClassMetadata的效果
System.out.println("==============ClassMetadata==============");
ClassMetadata classMetadata = metadata;
System.out.println(classMetadata.getClassName()); //com.fsx.maintest.MetaDemo
System.out.println(classMetadata.getEnclosingClassName()); //null 如果自己是內部類此處就有值了
System.out.println(StringUtils.arrayToCommaDelimitedString(classMetadata.getMemberClassNames())); //com.fsx.maintest.MetaDemo$InnerClass 若木有內部類返回空數組[]
System.out.println(StringUtils.arrayToCommaDelimitedString(classMetadata.getInterfaceNames())); // java.io.Serializable
System.out.println(classMetadata.hasSuperClass()); // true(只有Object這里是false)
System.out.println(classMetadata.getSuperClassName()); // java.util.HashMap

System.out.println(classMetadata.isAnnotation()); // false(是否是注解類型的Class,這里顯然是false)
System.out.println(classMetadata.isFinal()); // false
System.out.println(classMetadata.isIndependent()); // true(top class或者static inner class,就是獨立可new的)
// 演示AnnotatedTypeMetadata的效果
System.out.println("==============AnnotatedTypeMetadata==============");
AnnotatedTypeMetadata annotatedTypeMetadata = metadata;
System.out.println(annotatedTypeMetadata.isAnnotated(Service.class.getName())); // true(依賴的AnnotatedElementUtils.isAnnotated這個方法)
System.out.println(annotatedTypeMetadata.isAnnotated(Component.class.getName())); // true

System.out.println(annotatedTypeMetadata.getAnnotationAttributes(Service.class.getName())); //{value=serviceName}
System.out.println(annotatedTypeMetadata.getAnnotationAttributes(Component.class.getName())); // {value=repositoryName}(@Repository的value值覆蓋了@Service的)
System.out.println(annotatedTypeMetadata.getAnnotationAttributes(EnableAsync.class.getName())); // {order=2147483647, annotation=interface java.lang.annotation.Annotation, proxyTargetClass=false, mode=PROXY}

// 看看getAll的區別:value都是數組的形式
System.out.println(annotatedTypeMetadata.getAllAnnotationAttributes(Service.class.getName())); // {value=[serviceName]}
System.out.println(annotatedTypeMetadata.getAllAnnotationAttributes(Component.class.getName())); // {value=[, ]} --> 兩個Component的value值都拿到了,只是都是空串而已
System.out.println(annotatedTypeMetadata.getAllAnnotationAttributes(EnableAsync.class.getName())); //{order=[2147483647], annotation=[interface java.lang.annotation.Annotation], proxyTargetClass=[false], mode=[PROXY]}

// 演示AnnotationMetadata子接口的效果(重要)
System.out.println("==============AnnotationMetadata==============");
AnnotationMetadata annotationMetadata = metadata;
System.out.println(annotationMetadata.getAnnotationTypes()); // [org.springframework.stereotype.Repository, org.springframework.stereotype.Service, org.springframework.scheduling.annotation.EnableAsync]
System.out.println(annotationMetadata.getMetaAnnotationTypes(Service.class.getName())); // [org.springframework.stereotype.Component, org.springframework.stereotype.Indexed]
System.out.println(annotationMetadata.getMetaAnnotationTypes(Component.class.getName())); // [](meta就是獲取注解上面的注解,會排除掉java.lang這些注解們)

System.out.println(annotationMetadata.hasAnnotation(Service.class.getName())); // true
System.out.println(annotationMetadata.hasAnnotation(Component.class.getName())); // false(注意這里返回的是false)

System.out.println(annotationMetadata.hasMetaAnnotation(Service.class.getName())); // false(注意這一組的結果和上面相反,因為它看的是meta)
System.out.println(annotationMetadata.hasMetaAnnotation(Component.class.getName())); // true

System.out.println(annotationMetadata.hasAnnotatedMethods(Autowired.class.getName())); // true
annotationMetadata.getAnnotatedMethods(Autowired.class.getName()).forEach(methodMetadata -> {
System.out.println(methodMetadata.getClass()); // class org.springframework.core.type.StandardMethodMetadata
System.out.println(methodMetadata.getMethodName()); // getName
System.out.println(methodMetadata.getReturnTypeName()); // java.lang.String
});
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
像這些元數據,在框架設計時候很多時候我們都希望從File(Resource)里得到,而不是從Class文件里獲取,所以就是MetadataReader和MetadataReaderFactory。下面我也給出使用案例:

因為MetadataReader的實現類都是包級別的訪問權限,所以它的實例只能來自工廠

public static void main(String[] args) throws IOException {
CachingMetadataReaderFactory readerFactory = new CachingMetadataReaderFactory();
// 下面兩種初始化方式都可,效果一樣
//MetadataReader metadataReader = readerFactory.getMetadataReader(MetaDemo.class.getName());
MetadataReader metadataReader = readerFactory.getMetadataReader(new ClassPathResource("com/fsx/maintest/MetaDemo.class"));

ClassMetadata classMetadata = metadataReader.getClassMetadata();
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
Resource resource = metadataReader.getResource();

System.out.println(classMetadata); // org.springframework.core.type.classreading.AnnotationMetadataReadingVisitor@79079097
System.out.println(annotationMetadata); // org.springframework.core.type.classreading.AnnotationMetadataReadingVisitor@79079097
System.out.println(resource); // class path resource [com/fsx/maintest/MetaDemo.class]

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
總結
元數據,是框架設計中必須的一個概念,所有的流行框架里都能看到它的影子,包括且不限於Spring、SpringBoot、SpringCloud、MyBatis、Hibernate等。它的作用肯定是大大的,它能模糊掉具體的類型,能讓數據輸出變得統一,能解決Java抽象解決不了的問題,比如運用得最廣的便是注解,因為它不能繼承無法抽象,所以用元數據方式就可以完美行成統一的向上抽取讓它變得與類型無關,也就是常說的模糊效果,這便是框架的核心設計思想。

不管是ClassMetadata還是AnnotatedTypeMetadata都會有基於反射和基於ASM的兩種解決方案,他們能使用於不同的場景:

標准反射:它依賴於Class,優點是實現簡單,缺點是使用時必須把Class加載進來。
ASM:無需提前加載Class入JVM,所有特別特別適用於形如Spring應用掃描的場景(掃描所有資源,但並不是加載所有進JVM/容器~)
————————————————
版權聲明:本文為CSDN博主「_YourBatman」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/f641385712/article/details/88765470


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM