spring 系列之扫描Interface

前言

spring@ComponentScan("") 注解默认是不扫描interface的,一般在开发的时候我们不需要在interface上面添加 @Component 注解,添加上也是无效的。但我们在使用mybatis在进行项目开发的时候经常会使用mapper interface接口来注入到service层中,这是因为mybatis 会将我们需要的mapper 接口的interface 生成一个代理对象注入到service层中。其实我们重写spring 中的ClassPathBeanDefinitionScanner 来实现对interface 扫描到spring 容器中。

准备工作

spring 系列之扫描Interface
在com.boshrong.spring.mapper 中我们定义了两个接口。 我们要实现将这两个接口注入到Spring 容器中。

编写扫描类

package com.boshrong.mybatis;

import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.type.classreading.MetadataReader;

import java.io.IOException;
import java.util.Set;

public class  RongScanner extends ClassPathBeanDefinitionScanner {

    public RongScanner(BeanDefinitionRegistry registry) {
        super(registry);
    }

    @Override
    //判断是否为合格的compoent
    protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
        return metadataReader.getClassMetadata().isInterface();
    }

    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        return beanDefinition.getMetadata().isInterface();
    }

    @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);
        //返回的是beandefinition
        return beanDefinitionHolders;

    }
}

这个扫描类继承了ClassPathBeanDefinitionScanner,并重写了两个iisCandidateComponent 方法注意两个的参数是不一致的,让其支持对interface 扫描。然后重写了doScan方法,doScan方法 返回的是beandefinition.在spring 底层所有声明式bean的定义都是通过beandefinition来实现的。其基本结构就是下面形式

AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
//设置bean的类型
beanDefinition.setBeanClass(Aservice.class);
// 往spring 容器中注册
applicationContext.registerBeanDefinition("aservice",beanDefinition);

二 创建Register 相关类进行创建

package com.boshrong.mybatis;

import com.boshrong.spring.mapper.OrderMapper;
import com.boshrong.spring.mapper.UserMapper;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;

import java.io.IOException;

public class RongImportBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {

        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {

            // 扫描--->
            // 传入注册表
            String path="com.boshrong.spring.mapper";
            //扫描注册表
            RongScanner rongScanner=new RongScanner(registry);
            // return true 表示不用加compoent注解也能被扫描
            rongScanner.addIncludeFilter(new TypeFilter() {
                public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
                    return true;
                }
            });
            rongScanner.doScan(path); //BeanDefinition --> register

    }
}

我们实现ImportBeanDefinitionRegistrar 接口和registerBeanDefinitions 方法。这样的好处在于我们可以通过@Import(RongImportBeanDefinitionRegister.class) 导入相关类,因为有Spring提供的接口。spring 自动调用其中的方法。

运行结果

spring 系列之扫描Interface
我们可以在doScan上面打上断点,查看beanDefinitionHolders的值。断点结果如下。
spring 系列之扫描Interface

上一篇:CodeForces 1294 E.Obtain a Permutation (贪心)


下一篇:Obtain a Permutation 乱搞