元数据:数据的数据,比如Class就是一种元数据
可以看到顶层接口有两个:ClassMetadata
和AnnotatedTypeMetadata
注解上的注解,Spring
将其定义为元注解(meta-annotation
),如 @Component
标注在 @Service
上,@Component
就被称作为元注解。后面我们就将注解的注解称为元注解。
Class
的抽象和适配此接口的所有方法,都是获取class上的元素
public interface ClassMetadata {
/**
* Return the name of the underlying class.
*/
String getClassName();
/**
* Return whether the underlying class represents an interface.
*/
boolean isInterface();
/**
* Return whether the underlying class represents an annotation.
* @since 4.1
*/
boolean isAnnotation();
/**
* Return whether the underlying class is marked as abstract.
*/
boolean isAbstract();
/**
* // 是否允许创建 不是接口且不是抽象类 这里就返回true了
*
*/
boolean isConcrete();
/**
* Return whether the underlying class is marked as 'final'.
*/
boolean isFinal();
/**
* 是否是独立的(能够创建对象的) 比如是Class、或者内部类、静态内部类
*/
boolean isIndependent();
/**
* 是否有内部类
*/
boolean hasEnclosingClass();
/**
* Return the name of the enclosing class of the underlying class,
* or {@code null} if the underlying class is a top-level class.
*/
@Nullable
String getEnclosingClassName();
/**
* Return whether the underlying class has a super class.
*/
boolean hasSuperClass();
/**
* Return the name of the super class of the underlying class,
* or {@code null} if there is no super class defined.
*/
@Nullable
String getSuperClassName();
// 会把实现的所有接口名称都返回 具体依赖于Class#getSuperclass
String[] getInterfaceNames();
// 基于:Class#getDeclaredClasses 返回类中定义的公共、私有、保护的内部类
String[] getMemberClassNames();
}
继承树如下
基于Java标准的(Standard)反射实现元数据的获取
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.core.type;
import java.lang.reflect.Modifier;
import java.util.LinkedHashSet;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* {@link ClassMetadata} implementation that uses standard reflection
* to introspect a given {@code Class}.
*
* @author Juergen Hoeller
* @since 2.5
*/
public class StandardClassMetadata implements ClassMetadata {
private final Class> introspectedClass;
/**
* Create a new StandardClassMetadata wrapper for the given Class.
* @param introspectedClass the Class to introspect
*/
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 isConcrete() {
return !(isInterface() || isAbstract());
}
@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
//是否有内部类
public boolean hasEnclosingClass() {
return (this.introspectedClass.getEnclosingClass() != null);
}
@Override
@Nullable
//获取内部类的名称
public String getEnclosingClassName() {
Class> enclosingClass = this.introspectedClass.getEnclosingClass();
return (enclosingClass != null ? enclosingClass.getName() : null);
}
@Override
public boolean hasSuperClass() {
return (this.introspectedClass.getSuperclass() != 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);
}
}
它有个非常重要的子类:StandardAnnotationMetadata
它和注解密切相关
什么叫注解元素(AnnotatedElement
)?比如我们常见的Class、Method、Constructor、Parameter
等等都属于它的子类都属于注解元素。简单理解:只要能在上面标注注解都属于这种元素。Spring4.0
新增的这个接口提供了对注解统一的、便捷的访问,使用起来更加的方便高效了。
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.core.type;
import java.util.Map;
import org.springframework.lang.Nullable;
import org.springframework.util.MultiValueMap;
/**
* Defines access to the annotations of a specific type ({@link AnnotationMetadata class}
* or {@link MethodMetadata method}), in a form that does not necessarily require the
* class-loading.
*
* @author Juergen Hoeller
* @author Mark Fisher
* @author Mark Pollack
* @author Chris Beams
* @author Phillip Webb
* @author Sam Brannen
* @since 4.0
* @see AnnotationMetadata
* @see MethodMetadata
*/
public interface AnnotatedTypeMetadata {
// 此元素是否标注有此注解
// annotationName:注解全类
boolean isAnnotated(String annotationName);
//取得指定类型注解的所有的属性 - 值(k-v)
// annotationName:注解全类名
// classValuesAsString:若是true表示 Class用它的字符串的全类名来表示。这样可以避免Class被提前加载
@Nullable
Map getAnnotationAttributes(String annotationName);
@Nullable
Map getAnnotationAttributes(String annotationName, boolean classValuesAsString);
@Nullable
MultiValueMap getAllAnnotationAttributes(String annotationName);
@Nullable
MultiValueMap getAllAnnotationAttributes(String annotationName, boolean classValuesAsString);
}
它的继承树如下:
两个子接口相应的都提供了标准实现以及基于ASM
的Visitor
模式实现。
ASM 是一个通用的 Java 字节码操作和分析框架。它可以用于修改现有类或直接以二进制形式动态生成类。 ASM 虽然提供与其他 Java 字节码框架如 Javassist,CGLIB类似的功能,但是其设计与实现小而快,且性能足够高。
public interface MethodMetadata extends AnnotatedTypeMetadata {
/**
* Return the name of the method.
*/
String getMethodName();
/**
* Return the fully-qualified name of the class that declares this method.
*/
String getDeclaringClassName();
/**
* Return the fully-qualified name of this method's declared return type.
* @since 4.2
*/
String getReturnTypeName();
/**
* Return whether the underlying method is effectively abstract:
* i.e. marked as abstract on a class or declared as a regular,
* non-default method in an interface.
* @since 4.2
*/
boolean isAbstract();
/**
* Return whether the underlying method is declared as 'static'.
*/
boolean isStatic();
/**
* Return whether the underlying method is marked as 'final'.
*/
boolean isFinal();
/**
* Return whether the underlying method is overridable,
* i.e. not marked as static, final or private.
*/
boolean isOverridable();
}
StandardMethodMetadata
基于反射的标准实现,
MethodMetadataReadingVisitor
基于ASM
的实现的,继承自ASM``的org.springframework.asm.MethodVisitor
采用Visitor
的方式读取到元数据。
AnnotationMetadata
(重要)这是理解Spring
注解编程的必备知识,它是ClassMetadata
和AnnotatedTypeMetadata
的子接口,具有两者共同能力,并且新增了访问注解的相关方法。可以简单理解为它是对注解的抽象。
经常这么使用得到注解里面所有的属性值:
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(annoMetadata, annType);
public interface AnnotationMetadata extends ClassMetadata, AnnotatedTypeMetadata {
//拿到当前类上所有的注解的全类名(注意是全类名)
Set getAnnotationTypes();
// 拿到指定的注解类型
//annotationName:注解类型的全类名
Set getMetaAnnotationTypes(String annotationName);
// 是否包含指定注解 (annotationName:全类名)
boolean hasAnnotation(String annotationName);
//这个厉害了,用于判断注解类型自己是否被某个元注解类型所标注
//依赖于AnnotatedElementUtils#hasMetaAnnotationTypes
boolean hasMetaAnnotation(String metaAnnotationName);
// 类里面只有有一个方法标注有指定注解,就返回true
//getDeclaredMethods获得所有方法, AnnotatedElementUtils.isAnnotated是否标注有指定注解
boolean hasAnnotatedMethods(String annotationName);
// 返回所有的标注有指定注解的方法元信息。注意返回的是MethodMetadata 原理基本同上
Set getAnnotatedMethods(String annotationName);
}
元数据,是框架设计中必须的一个概念,所有的流行框架里都能看到它的影子,包括且不限于Spring、SpringBoot、SpringCloud、MyBatis、Hibernate
等。它的作用肯定是大大的,它能模糊掉具体的类型,能让数据输出变得统一,能解决Java抽象解决不了的问题,比如运用得最广的便是注解,因为它不能继承无法抽象,所以用元数据方式就可以完美行成统一的向上抽取让它变得与类型无关,也就是常说的模糊效果,这便是框架的核心设计思想。
不管是ClassMetadata
还是AnnotatedTypeMetadata
都会有基于反射和基于ASM的两种解决方案,他们能使用于不同的场景:
Spring
应用扫描的场景(扫描所有资源,但并不是加载所有进JVM/容器~)