手写Spring源码06 - 元数据读取器 MetadataReader 设计与实现(五)

本篇记录注解类型映射的实现,如下图圈出的部分:
在这里插入图片描述

注解类型映射的实现
注解过滤器定义 - AnnotationFilter

代码实现:

package cn.zhanghongyang.core.annotation;

import java.lang.annotation.Annotation;

/**
 * @Author: zhanghongyang
 * @Description: 注解过滤器
 */
public interface AnnotationFilter {

    /**
     * 声明过滤器,包含两个包
     */
    AnnotationFilter PLAIN = packages("java.lang", "org.springframework.lang");

    /**
     * 生成过滤器
     * @param pagckages 包名
     * @return
     */
    static AnnotationFilter packages(String... pagckages){
        return new PackageAnnotationFilter(pagckages);
    }

    /**
     * 匹配验证
     * @param typeName 类型名称
     * @return
     */
    boolean matches(String typeName);

    /**
     * 匹配验证
     * @param type 类型
     * @return
     */
    default boolean matches(Class<?> type){
        return matches(type.getName());
    }

    /**
     * 匹配验证
     * @param annotation 注解
     * @return
     */
    default boolean matches(Annotation annotation){
        return matches(annotation.annotationType());
    }
}
注解过滤器的实现类(包注解过滤器) - PackageAnnotationFilter

主要根据注解的包进行过滤

功能演示:

//构建org.springframework.lang包的过滤器
AnnotationFilter annotationFilter = new PackagesAnnotationFilter("org.springframework.lang");
//匹配验证
boolean matches = annotationFilter.matches("org.springframework.lang.Nullable");
Assert.isTrue(matches);

代码实现:

package cn.zhanghongyang.core.annotation;

import java.util.Arrays;

/**
 * @Author: zhanghongyang
 * @Description: 包注解过滤器
 */
public class PackageAnnotationFilter implements AnnotationFilter{
    
    //过滤包名的前缀
    private String[] prefixes;
    
    public PackageAnnotationFilter(String... packages) {
        prefixes = new String[packages.length];
        for (int i = 0; i < packages.length; i++) {
            prefixes[i] = packages[i] + ".";
        }
        Arrays.sort(prefixes);
    }

    @Override
    public boolean matches(String typeName) {
        for (String prefix : prefixes) {
            if (typeName.startsWith(prefix)){
                return true;
            }
        }
        return false;
    }
}

注解扫描器 - AnnotationsScanner

功能演示:

功能介绍篇的案例@Zhy上打了@Zhy2注解,测试类打了@Zhy注解,测试案例代码如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Zhy2
public @interface Zhy {

	@AliasFor(value = "name")
	String value() default "";

	String name() default "";
  
}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Zhy2 {
}

@Zhy(name = "张红洋")
public class ZhyTest {
  public static void main(String[] args) {
		Zhy annotation = ZhyTest.class.getAnnotation(Zhy.class);
		Annotation[] metaAnnotations = AnnotationsScanner.getDeclaredAnnotations(annotation.annotationType(), false);
		System.out.println(metaAnnotations);
	}
}

在这里插入图片描述

代码实现:

package cn.zhanghongyang.core.annotation;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author: zhanghongyang
 * @Date: 2021/8/12 14:02
 * @Description: 注解扫描器
 */
public abstract class AnnotationsScanner {

    private static final Map<AnnotatedElement, Annotation[]> declaredAnnotationCache = new ConcurrentHashMap<>(16);

    /**
     * 获取source的过滤后的注解,并缓存到内部
     * @param source 需要扫描的元素(可以打注解的元素)
     * @return source 过滤后的注解
     */
    static Annotation[] getDeclaredAnnotations(AnnotatedElement source){
      
        //从缓存中获取
        Annotation[] annotations = declaredAnnotationCache.get(source);

        if (annotations == null){
            //获取到注解
            annotations = source.getDeclaredAnnotations();
            for (int i = 0; i < annotations.length; i++) {
                //过滤判断,可以过滤掉Target等元注解
                if (isIgnorable(annotations[i].annotationType())){
                    //如果是被忽略的赋值为null
                    annotations[i] = null;
                }
            }
            //存入缓存
            declaredAnnotationCache.put(source, annotations);
        }
      
        //返回的时候需要复制一份,防止缓存中的数据被修改
        return annotations.clone();
    }

    private static boolean isIgnorable(Class<?> annotationType) {
        //使用过滤器过滤
        return AnnotationFilter.PLAIN.matches(annotationType);
    }
}
注解类型的映射类 - AnnotationTypeMapping

主要作用保存注解的上下级关系,处理别名的映射关系

代码实现:

package cn.zhanghongyang.core.annotation;

import java.lang.annotation.Annotation;

/**
 * @Author: zhanghongyang
 * @Description: 注解类型的映射,这里忽略了别名的处理
 */
public class AnnotationTypeMapping {

    //来源
    private AnnotationTypeMapping source;
    
    //注解是根(最开始的注解)
    private AnnotationTypeMapping root;

    //元注解类型
    private Class<? extends Annotation> annotationType;

    //元注解
    private Annotation annotation;

    //距离
    private int distance;

    public AnnotationTypeMapping(AnnotationTypeMapping source, Class<? extends Annotation> annotationType, Annotation annotation) {
        this.source = source;
        this.annotationType = annotationType;
        this.annotation = annotation;
        //如果没有来源,则距离是0,否则+1
        this.distance = source == null ? 0 : source.getDistance() + 1;
        //如果来源不是空,则获取来源的源,否则就是自己,这里的值是最开始的那个注解
        this.root = source != null ? source.getSource(): this;
    }

    public AnnotationTypeMapping getSource() {
        return source;
    }

    public AnnotationTypeMapping getRoot() {
        return root;
    }

    public Class<? extends Annotation> getAnnotationType() {
        return annotationType;
    }

    public Annotation getAnnotation() {
        return annotation;
    }

    public int getDistance() {
        return distance;
    }
}
注解类型映射关系的集合 - AnnotationTypeMappings

获取注解的注解,注解的注解的注解…,每个注解使用AnnotationTypeMeppings保存。内部使用了两个缓存,一个缓存过滤器和注解映射集合的关系,一个缓存注解类型和注解映射集合的关系。

功能演示:

实例同上,@Zhy上打了@Zhy2,@Zhy2上打了@Zhy3。距离表示距离source的距离

在这里插入图片描述

代码实现

package cn.zhanghongyang.core.annotation;

import java.lang.annotation.Annotation;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author: zhanghongyang
 * @Description:
 * 1 添加过滤器
 * 2 获取获取器的Cache,没有则创建Cache
 *      2.1 从Cache中获取注解对应的 AnnotationTypeMappings,AnnotationTypeMappings中存储了注解的元注解信息,如果不存在则创建
 *          2.1.1 创建AnnotationTypeMappings,广度优先遍历获取元注解
 *              2.1.1.1 使用AnnotationsScanner获取注解的所有元注解,并使用 AnnotationFilter.PLAIN 过滤符合条件的注解,不符合的置为null,并且缓存起来
 *          2.1.2 再次使用步骤1添加的过滤器和其他条件过滤,符合添加的加入到队列中
 */
public class AnnotationTypeMappings {

    /** Spring中使用了自定义的ConcurrentReferenceHashMap,是可以指定引用基本的ConcurrentHashMap,默认级别是软引用,在内存不足时会被回收,适合做缓存 */
    private static final Map<AnnotationFilter, Cache> standardRepeatablesCache = new ConcurrentHashMap<>();

    static AnnotationTypeMappings forAnnotationType(Class<? extends Annotation> annotationType){
        //增加过滤器
        return forAnnotationType(annotationType, AnnotationFilter.PLAIN);
    }

    static AnnotationTypeMappings forAnnotationType(Class<? extends Annotation> annotationType, AnnotationFilter annotationFilter){
        // 将过滤器传递给Cache,Cache没有使用会再传递给AnnotationTypeMappings,
        // 最终给还是在AnnotationTypeMappings中筛选注解使用,最终效果是从静态->非静态传递的过程
        return standardRepeatablesCache.computeIfAbsent(annotationFilter, key -> new Cache(annotationFilter)).get(annotationType);
    }

    /**********************上面的静态变量和方法是缓存注解过滤器和Cache对应关系,只有一份***********************/

    //保存注解的元注解,会封装成AnnotationTypeMapping类型
    private final List<AnnotationTypeMapping> mappings;

    private final AnnotationFilter filter;

    public AnnotationTypeMappings(AnnotationFilter filter, Class<? extends Annotation> annotationType) {
        this.filter = filter;
        this.mappings = new ArrayList<>();
        //层序遍历元注解
        addAllMappings(annotationType);
    }

    private void addAllMappings(Class<? extends Annotation> annotationType){
        //层序遍历辅助队列,双端队列
        Deque<AnnotationTypeMapping> deque = new ArrayDeque<>();
        addIfPossible(deque, null, annotationType, null);
        while (!deque.isEmpty()){
            AnnotationTypeMapping mapping = deque.removeFirst();
            this.mappings.add(mapping);
            //获取下一层注解并添加到队列中
            addMetaAnnotationToQueue(deque, mapping);
        }
    }

    /**
     * 获取source的元注解添加到deque
     * @param deque 队列
     * @param source 注解
     */
    private void addMetaAnnotationToQueue(Deque<AnnotationTypeMapping> deque, AnnotationTypeMapping source){
        //获取到元注解
        Annotation[] metaAnnotations = AnnotationsScanner.getDeclaredAnnotations(source.getAnnotationType());
        for (Annotation metaAnnotation : metaAnnotations) {
            //筛选掉为null,符合filter,还有已经存在的
            if (!isMappable(source, metaAnnotation)){
                continue;
            }
            addIfPossible(deque, source, metaAnnotation.annotationType(), metaAnnotation);
        }
    }

    /**
     * 向队列中添加AnnotationTypeMapping
     * @param deque 队列
     * @param annotation 注解
     */
    private void addIfPossible(Deque<AnnotationTypeMapping> deque, AnnotationTypeMapping source, Class<? extends Annotation> annotationType, Annotation annotation){
        deque.addLast(new AnnotationTypeMapping(source, annotationType, annotation));
    }

    private boolean isMappable(AnnotationTypeMapping source, Annotation metaAnnotation){
        //判断null会把AnnotationsScanner.getDeclaredAnnotations返回数组中的null过滤掉
        return (metaAnnotation != null && !this.filter.matches(metaAnnotation)) && !isAlreadyMapped(source, metaAnnotation);
    }

    /**
     * 判断是否已经存在
     * 从注解开始下找,如果找到metaAnnotation说明已经存在了
     * @param source
     * @param metaAnnotation
     * @return
     */
    private boolean isAlreadyMapped(AnnotationTypeMapping source, Annotation metaAnnotation){
        AnnotationTypeMapping mapping = source;
        while (mapping !=  null){
            if (mapping.getAnnotationType() == metaAnnotation.annotationType()){
                return true;
            }
            mapping = mapping.getSource();
        }
        return false;
    }

    public AnnotationTypeMapping get(int index){
        //index == 0 时 就是注解本身
        return this.mappings.get(index);
    }

    /**
     * 主要存储 注解->元注解(在AnnotationTypeMappings存储) 关系
     * 因为要在静态方法中使用,所有用static修饰
     */
    private static class Cache{

        private final Map<Class<? extends Annotation>, AnnotationTypeMappings> mappings;

        //这里保存注解过滤器是为了传递给AnnotationMappings使用
        private AnnotationFilter filter;

        public Cache(AnnotationFilter filter) {
            this.filter = filter;
            this.mappings = new ConcurrentHashMap<>();
        }

        public AnnotationTypeMappings get(Class<? extends Annotation> annotationType){
            //如果不存在就创建
            return mappings.computeIfAbsent(annotationType, this::createMappings);
        }

        public AnnotationTypeMappings createMappings(Class<? extends Annotation> annotationType){
            //创建AnnotationTypeMappings的时候,会层序遍历元注解
            return new AnnotationTypeMappings(filter, annotationType);
        }
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值