从零开始造Spring05---实现spring注解-1

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014534808/article/details/82315756

前言

前几篇我们实现了配置的方式实现Bean的生成和注入,接下来我们将要通过注解的方式来实现这一过程。这是学习刘欣老师《从零开始造Spring》课程的学习笔记。在实现的过程中我们需要用到ASM的技术,具体可以参考ASM技术

实现思路

  1. 读取XML文件
  2. 对指定的package 进行扫描(scan) ,找到那些标记为@Component的类,创建BeanDefinition
    2.1 把一个package下面的class变成resource
    2.2 使用ASM读取Resource中的注解
    2.3 创建BeanDefinition
  3. 通过BeanDefinition创建Bean实例,根据注解来注入。

具体实现

我们首先来了解下相关的注解,在此处,我们首先实现了两个最基本的注解@Component 注解和@Autowired 注解,注解的本质就是元数据。我们已@Autowired为例。

/**
 *
 * 注解本质上就是元数据,
 * @Target 标注注解的使用地方
 * @Documented 说注解就是一个元素,可以被文档化
 * Created by xiang.wei on 2018/7/14
 *
 */
 //构造器,字段,方法。
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
//保留到运行时
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {

    /**
     * Declares whether the annotated dependency is required.
     * <p>Defaults to {@code true}.
     */
    boolean required() default true;
}

我们通过PackageResourceLoader类来将base-package 中配置的包下加载出对应的Resource
关键代码如下:

   public Resource[] getResources(String basePackage) throws IOException {
        Assert.notNull(basePackage, "basePackage must not be null");
        String location = ClassUtils.convertClassNameToResourcePath(basePackage);
        ClassLoader cl = getClassLoader();
        URL url = cl.getResource(location);
        File rootDir = new File(url.getFile());
        Set<File> matchingFiles = retrieveMatchingFiles(rootDir);
        Resource[] result = new Resource[matchingFiles.size()];
        int i = 0;
        for (File file : matchingFiles) {
            result[i++] = new FileSystemResource(file);
        }
        return result;
    }

调试如下:
PackageResourceLoader调试结果

实现两个Visitor,实现SimpleMetaDataReader 这两步参考ASM在Spring中的应用

实现Scanner(对ASM的抽象)

这里写图片描述
如类图所示,我们抽象了一个MetadataReader接口,该接口依赖于AnnotationVisitor抽象类和ClassVisitor抽象类,而AnnotationAttributesReadingVisitor类和ClassMetadataReadingVisitor类又是这两个抽象类的实现。由此我们就完全隐藏了AnnotationAttributesReadingVisitor类和ClassMetadataReadingVisitor
测试代码

public class MetadataReaderTest {

    @Test
    public void testGetMetadata() throws IOException {
        ClassPathResource resource = new ClassPathResource("com/jay/spring/service/v4/PetStoreService.class");
        MetadataReader reader = new SimpleMetadataReader(resource);

        AnnotationMetadata amd = reader.getAnnotationMetadata();

        String annotation = Component.class.getName();

        Assert.assertTrue(amd.hasAnnotation(annotation));
        AnnotationAttributes attributes = amd.getAnnotationAttributes(annotation);
        Assert.assertEquals("petStoreService", attributes.get("value"));

        Assert.assertFalse(amd.isAbstract());
        Assert.assertFalse(amd.isFinal());
        Assert.assertEquals("com.jay.spring.service.v4.PetStoreService", amd.getClassName());
    }
}

ClassMetadataReadingVisitor

    /**
     * @param version
     * @param access
     * @param name
     * @param signature
     * @param supername
     * @param interfaces
     *
     *
     * 这个涉及到了Java的字节码, 在Java字节码中,常量池结束之后,
     * 有两个字节表示访问标识(access_flags),
     * 这个标识用于识别一些类或者接口层次的访问信息,
     * 例如这个Class是类或者接口,是否为public ,abstract ,final 等等
     * 对类的处理,判断类的基本情况
     *
     */
    //
    @Override
    public void visit(int version, int access, String name, String signature, String supername, String[] interfaces) {
        this.className = ClassUtils.convertResourcePathToClassName(name);
        this.isInterface = ((access & Opcodes.ACC_INTERFACE) != 0);
        this.isAbstract = ((access & Opcodes.ACC_ABSTRACT) != 0);
        this.isFinal = ((access & Opcodes.ACC_FINAL) != 0);
        if (supername != null) {
            this.superClassName = ClassUtils.convertResourcePathToClassName(supername);
        }
        this.interfaces = new String[interfaces.length];
        for (int i = 0; i < interfaces.length; i++) {
            this.interfaces[i] = ClassUtils.convertResourcePathToClassName(interfaces[i]);
        }
    }

AnnotationMetadataReadingVisitor

public class AnnotationMetadataReadingVisitor extends  ClassMetadataReadingVisitor implements AnnotationMetadata {
    private final Set<String> annotationSet = new LinkedHashSet<String>(4);
    private final Map<String, AnnotationAttributes> attributeMap = new LinkedHashMap<String, AnnotationAttributes>(4);

    public AnnotationMetadataReadingVisitor() {

    }
    @Override
    public AnnotationVisitor visitAnnotation(final String desc, boolean visible) {
        String className = Type.getType(desc).getClassName();
        this.annotationSet.add(className);
        return new AnnotationAttributesReadingVisitor(className, this.attributeMap);
    }
    @Override
    public Set<String> getAnnotationTypes() {
        return this.annotationSet;
    }

    @Override
    public boolean hasAnnotation(String annotationType) {
        return this.annotationSet.contains(annotationType);
    }

    @Override
    public AnnotationAttributes getAnnotationAttributes(String annotationType) {
        return this.attributeMap.get(annotationType);
    }

    @Override
    public boolean hasSuperClass() {
        return false;
    }
}

SimpleMetadataReader

    public SimpleMetadataReader(Resource resource) throws IOException {
        // 提高一点性能吧
        InputStream inputStream = new BufferedInputStream(resource.getInputStream());
        ClassReader classReader;

        try {
            classReader = new ClassReader(inputStream);
        } finally {
            inputStream.close();
        }

        AnnotationMetadataReadingVisitor visitor = new AnnotationMetadataReadingVisitor();
        classReader.accept(visitor, ClassReader.SKIP_DEBUG);
        this.annotationMetadata = visitor;
        this.classMetadata = visitor;
        this.resource = resource;
    }

这里写图片描述
ScannedGenericBeanDefinition 专门用来表达通过Scann扫描出的BeanDefiniton。
ClassPathBeanDefinitionScanner

/**
 * 1. 给定一个package的名称列表,例如
 org.litespring.service.v4,org.litespring.dao.v4"

 2. 对指定的package 进行扫描(scan),找到那些标记为@Component 的类,创建ScannedGenericBeanDefinition,并且注册到BeanFactory中。

 * Created by xiang.wei on 2018/7/15
 *
 * @author xiang.wei
 */
public class ClassPathBeanDefinitionScanner {
    private final BeanDefinitionRegistry registry;

    private PackageResourceLoader resourceLoader = new PackageResourceLoader();

    private final Log logger = LogFactory.getLog(getClass());

    private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();

    public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
        this.registry = registry;
    }

    /**
     *
     * @param packagesToScan 传入的base-package 字符串
     * @return
     */
    public Set<BeanDefinition> doScan(String packagesToScan) {
        String[] basePackages = StringUtils.tokenizeToStringArray(packagesToScan, ",");

        Set<BeanDefinition> beanDefinitions = new LinkedHashSet<BeanDefinition>();
//      对每一个basePackages进行循环
        for (String basePackage : basePackages) {
            Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
            for (BeanDefinition candidate : candidates) {
                beanDefinitions.add(candidate);
                registry.registerBeanDefinition(candidate.getID(), candidate);
            }
        }
        return beanDefinitions;
    }

    /**
     *
     * @param basePackage
     * @return
     */
    public Set<BeanDefinition> findCandidateComponents(String basePackage) {
        Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
        try {
//            先拿到Resource
            Resource[] resources = this.resourceLoader.getResources(basePackage);
            for (Resource resource : resources) {
                try {
                    MetadataReader metadataReader = new SimpleMetadataReader(resource);
                    //  通过metadataReader 获取AnnotationMetadata 看看其是否有Component注解
                    if (metadataReader.getAnnotationMetadata().hasAnnotation(Component.class.getName())) {
//实例化一个ScannedGenericBeanDefinition
                        ScannedGenericBeanDefinition sbd=new ScannedGenericBeanDefinition(metadataReader.getAnnotationMetadata());
                        String beanName = this.beanNameGenerator.generateBeanName(sbd, this.registry);
                        sbd.setId(beanName);
                        candidates.add(sbd);
                    }
                } catch (Throwable ex) {
                    throw new BeanDefinitionStoreException("Failed to read candidate component class:" + resource, ex
                    );
                }
            }
        } catch (IOException e) {
            throw new BeanDefinitionStoreException("I/O failure during classpath scanning", e);
        }
        return candidates;
    }
}

ScannedGenericBeanDefinition

public class ScannedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
    private final AnnotationMetadata metadata;

    public ScannedGenericBeanDefinition(AnnotationMetadata metadata) {
        super();

        this.metadata = metadata;
        setBeanClassName(this.metadata.getClassName());

    }

    @Override
    public AnnotationMetadata getMetadata() {
        return this.metadata;
    }

}

XmlBeanDefinitionReader类的修改

    private void parseComponentElement(Element element) {
        String basePackages = element.attributeValue(BASE_PACKAGE_ATTRIBUTE);
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry);
        scanner.doScan(basePackages);

    }

源码地址

猜你喜欢

转载自blog.csdn.net/u014534808/article/details/82315756