Spring之class读取生成元数据流程

描述

在ClassPathBeanDefinitionScanner中看到spring通过扫描给定的包路径,获取到对应的class资源并判断是否生成BeanDefinition注册到IOC容器中,接下来根据源码来看spring是怎么通过class资源生成元数据

ClassPathBeanDefinitionScanner分析中看到 MetadataReaderFactory.getMetadataReader方法通过class资源(resource)生成MetadataReader

 

    // 此处通过asm将class文件读取成元数据模型
    MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);

下面跟读MetadataReaderFactory与MetadataReader代码查看class生成元数据。

MetadataReaderFactory

MetadataReaderFactory接口 ,MetadataReader的工厂接口。
允许缓存每个MetadataReader的元数据集。

  • 类关系图

metaReaderFactory.png

 

public interface MetadataReaderFactory {
    /**
     * 根据class名称创建MetadataReader
     */
    MetadataReader getMetadataReader(String className) throws IOException;

    /**
     * 根据class的Resource创建MetadataReader
     */
    MetadataReader getMetadataReader(Resource resource) throws IOException;

}

MetadataReaderFactory接口提供两个方法:

  1. 根据class名称生成MetadataReader
  2. 根据class的Resource生成MetadataReader
  • SimpleMetadataReaderFactory

 

public class SimpleMetadataReaderFactory implements MetadataReaderFactory {
    // 资源加载器,此类根据路径将给定的path生成IO流资源
    private final ResourceLoader resourceLoader;
    @Override
    public MetadataReader getMetadataReader(String className) throws IOException {
        try {
            //根据classname生成class对应的资源路径
            String resourcePath = ResourceLoader.CLASSPATH_URL_PREFIX +
                    ClassUtils.convertClassNameToResourcePath(className) + ClassUtils.CLASS_FILE_SUFFIX;
            //获取classname的IO流资源     
            Resource resource = this.resourceLoader.getResource(resourcePath);
            //调用资源创建MetadataReader
            return getMetadataReader(resource);
        }
        catch (FileNotFoundException ex) {
        }
    }
    
    /**
     *  根据class资源创建MetadataReader 默认实现
     */
    @Override
    public MetadataReader getMetadataReader(Resource resource) throws IOException {
        return new SimpleMetadataReader(resource, this.resourceLoader.getClassLoader());
    }

}

SimpleMetadataReaderFactory类为MetadataReaderFactory的简单实现,默认实现了MetadataReaderFactory的两个方法

  • 在getMetadataReader(String className) 方法中根据className创建class的Resource,然后调用getMetadataReader(Resource resource)
  • 在getMetadataReader(Resource resource) 方法中默认创建了SimpleMetadataReader
  • CachingMetadataReaderFactory

 

public class CachingMetadataReaderFactory extends SimpleMetadataReaderFactory {
    //默认的缓存大小
    public static final int DEFAULT_CACHE_LIMIT = 256;
    //内存缓存列表,Resource-MetadataReader的映射缓存
    @Nullable
    private Map<Resource, MetadataReader> metadataReaderCache;
    
    @Override
    public MetadataReader getMetadataReader(Resource resource) throws IOException {
        if (this.metadataReaderCache instanceof ConcurrentMap) {
        
            MetadataReader metadataReader = this.metadataReaderCache.get(resource);
            if (metadataReader == null) {
                metadataReader = super.getMetadataReader(resource);
                //缓存到本地缓存
                this.metadataReaderCache.put(resource, metadataReader);
            }
            return metadataReader;
        }
        else if (this.metadataReaderCache != null) {
            synchronized (this.metadataReaderCache) {
                MetadataReader metadataReader = this.metadataReaderCache.get(resource);
                if (metadataReader == null) {
                    metadataReader = super.getMetadataReader(resource);
                //缓存到本地缓存   this.metadataReaderCache.put(resource, metadataReader);
                }
                return metadataReader;
            }
        }
        else {
            return super.getMetadataReader(resource);
        }
    }
}

CachingMetadataReaderFactory 类在SimpleMetadataReaderFactory的基础上增加了缓存功能,对Resource-MetadataReader的映射做了本地缓存

MetadataReader

spring 对MetadataReader的描述为:Simple facade for accessing class metadata,as read by an ASM.大意是通过ASM读取class IO流资源组装访问元数据的门面接口

  • 类关系图

MetadataReader.png

  • MetadataReader

 

public interface MetadataReader {

    /**
     * 返回class文件的IO资源引用
     */
    Resource getResource();

    /**
     * 为基础class读取基本类元数据,返回基础类的元数据。
     */
    ClassMetadata getClassMetadata();

    /**
     *为基础类读取完整的注释元数据,包括注释方法的元数据。返回基础类的完整注释元数据
     */
    AnnotationMetadata getAnnotationMetadata();
}

MetadataReader接口提供三个方法:

  1. 返回class文件的IO资源引用
  2. 返回基础类的元数据
  3. 返回基础类的完整注释元数据
  • SimpleMetadataReader

 

final class SimpleMetadataReader implements MetadataReader {

    //class类IO流资源引用
    private final Resource resource;

     //class类元数据
    private final ClassMetadata classMetadata;
     //class类完整注释元数据
    private final AnnotationMetadata annotationMetadata;

    /**
     * 构建函数,用于通过过ASM字节码操控框架读取class读取class资源流
     */
    SimpleMetadataReader(Resource resource, @Nullable ClassLoader classLoader) throws IOException {
        // 获取class类IO流
        InputStream is = new BufferedInputStream(resource.getInputStream());
        ClassReader classReader;
        try {
            //通过ASM字节码操控框架读取class
            classReader = new ClassReader(is);
        }
        catch (IllegalArgumentException ex) {
        }
        finally {
            is.close();
        }

        //注解元数据读取访问者读取注解元数据
        AnnotationMetadataReadingVisitor visitor = new AnnotationMetadataReadingVisitor(classLoader);
        classReader.accept(visitor,ClassReader.SKIP_DEBUG);
        //注解元数据
        this.annotationMetadata = visitor;
        //class元数据
        this.classMetadata = visitor;
        this.resource = resource;
    }


    @Override
    public Resource getResource() {
        return this.resource;
    }

    @Override
    public ClassMetadata getClassMetadata() {
        //返回当前类元数据
        return this.classMetadata;
    }

    @Override
    public AnnotationMetadata getAnnotationMetadata() {
        //返回当前类的注解元数据
        return this.annotationMetadata;
    }

}

SimpleMetadataReader 为MetadataReader的默认实现,在创建SimpleMetadataReader通过ASM字节码操控框架读取class读取class资源流生成classMetadata与annotationMetadata

元数据模型

类元数据模型在包org.springframework.core.type下,是spring对class文件的描述单元,包含ClassMetadata,MethodMetadata,AnnotationMetadata等元数据,都是对外提供对class属性的访问,同时这些元数据是通过ASM字节码框架解析字节码获取生成。

  • ClassMetadata

提供对class类的信息访问

 

public interface ClassMetadata {

   //返回当前class名称
    String getClassName();
   //返回当前class是否为接口
    boolean isInterface();
    //返回当前class是否为注解
    boolean isAnnotation();
    //返回当前class是否为抽象类
    boolean isAbstract();

    boolean isConcrete();
    //返回当前class是否为final修饰
    boolean isFinal();

    boolean isIndependent();

    boolean hasEnclosingClass();

    String getEnclosingClassName();

    boolean hasSuperClass();

    String getSuperClassName();

    String[] getInterfaceNames();

    String[] getMemberClassNames();

}
  • AnnotationMetadata

提供对class类里的注解信息访问

 

public interface AnnotationMetadata extends ClassMetadata, AnnotatedTypeMetadata {

    Set<String> getAnnotationTypes();

    Set<String> getMetaAnnotationTypes(String annotationName);

    boolean hasAnnotation(String annotationName);

    boolean hasMetaAnnotation(String metaAnnotationName);

    boolean hasAnnotatedMethods(String annotationName);

    Set<MethodMetadata> getAnnotatedMethods(String annotationName);

}
  • MethodMetadata

提供对class类里方法信息的访问

 

public interface MethodMetadata extends AnnotatedTypeMetadata {
    String getMethodName();
    String getDeclaringClassName();
    String getReturnTypeName();
    boolean isAbstract();
    boolean isStatic();
    boolean isFinal();
    boolean isOverridable();

}

通过ClassPathBeanDefinitionScanner与生成元数据流程部分我们可以看到spring对class的完整操作

  1. 将class文件生成IO流的Resource
  2. 通过ASM字节码框架根据Resource创建元数据模型
  3. 根据元数据模型以及Resource生成BeanDefinition(bean定义)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值