zoukankan      html  css  js  c++  java
  • @Import导入自定义选择器

    @Import导入自定义选择器

    之前一篇博文:Spring中的@Import注解已经详细介绍了@Import注解,不赘述。

    需求描述

    通过@import注解自定义组件选择器,将满足我们自定义的规则的bean导入到ioc容器中

    项目结构

    案例代码

    首先是UserService接口及其实现类

    public interface UserService {
         void saveUser();
    }
    
    // 注意这里我们没有加入@service注解,因为我们将不采用@componentScan去指定扫描的注解。
    public class UserServiceImpl implements UserService {
    
        @Override
        public void saveUser() {
            System.out.println("保存用户");
        }
    }
    

    配置类:

    @Configuration
    @ComponentScan("com.helius")
    @Import(CustomeImportSelector.class)
    public class SpringConfiguration {
    
    }
    

    这里必须明确:尽管我们在配置上类加了@ComponentScan注解,但是@ComponentScan默认的扫描规则是扫描指定包下的@Service、@Component、@Repository、@Controller

    但是这里我们在com.helius包下的类上没有加这些注解


    自定义类型选择器

    package importselect;
    
    import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.ImportSelector;
    import org.springframework.core.io.support.PropertiesLoaderUtils;
    import org.springframework.core.type.AnnotationMetadata;
    import org.springframework.core.type.filter.AspectJTypeFilter;
    import org.springframework.core.type.filter.TypeFilter;
    
    import java.io.IOException;
    import java.util.HashSet;
    import java.util.Map;
    import java.util.Properties;
    import java.util.Set;
    
    /**
     * //返回值,就是到导入到容器中的组件全类名
     * //AnnotationMetadata:当前标注@Import注解的类的所有注解信息
     * 自定义导入器
     *
     * @Author Helius
     * @Create 2019-10-31-20:11
     */
    public class CustomeImportSelector implements ImportSelector {
        /**
         * 实现获取要导入类的字节码
         * 需求:导入的过滤规则TypeFilter采用aspectj表达式的方式
         */
        //表达式(ASPECTJ表达式)
        private String expression;
    
        /**
         * 默认构造函数
         * 用于读取配置文件,给表达式赋值
         */
        public CustomeImportSelector() {
            try {
    /*            InputStream resourceAsStream = CustomeImportSelector.class.getResourceAsStream("/customeimport.properties");
                Properties properties = new Properties();
                properties.load(resourceAsStream);*/
    
                //1.获取properties对象
                Properties properties =
                        PropertiesLoaderUtils.loadAllProperties("customeimport.properties");
                //2.给expression赋值
                expression = properties.getProperty("custome.importselector.expression");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            //1.定义扫描包的名称
            String[] basePackages = null;
            //2.判断有@Improt注解的类上是否有@ComponentScan注解
            if (importingClassMetadata.hasAnnotation(ComponentScan.class.getName())) {
                //3.取出@ComponentScan注解的属性(basePackages/value)
                Map<String, Object> annotationAttributes =
                        importingClassMetadata.getAnnotationAttributes(ComponentScan.class.getName());
                //4.取出属性名称为basePackages属性的值
                basePackages = (String[]) annotationAttributes.get("basePackages");
            }
            //5.判断是否有此属性(如果没有ComponentScan注解则属性值为null,如果有 ComponentScan注解,则basePackages默认为空数组)
            if (basePackages == null || basePackages.length == 0) {
                String basePackage = null;
                try {
                    // 6.取出包含@import注解的类所在包的名称
                    basePackage = Class.forName(importingClassMetadata.getClassName()).getPackage().getName();
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
                //7.存入数组中
                basePackages = new String[]{basePackage};
            }
            //8.创建类路径扫描器 参数的含义:表明不使用默认过滤规则
            ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
            //9.创建类型过滤器(此处使用AspectJ表示式类型过滤器)
            TypeFilter typeFilter = new AspectJTypeFilter(expression,CustomeImportSelector.class.getClassLoader());
            //10.把类型过滤器添加到扫描器中
            scanner.addIncludeFilter(typeFilter);
            //11.定义要扫描类的全限定类名集合
            Set<String> classes = new HashSet<>();
            //12.填充集合的内容
            for (String basePackage : basePackages) {
                scanner.findCandidateComponents(basePackage).forEach(beanDefinition -> classes.add(beanDefinition.getBeanClassName()));
            }
            //13.按照方法的返回值要求,返回全限定类名的数组
            return classes.toArray(new String[classes.size()]);
        }
    }
    
    

    配置文件

    custome.importselector.expression= com.helius.service.impl.*
    

    这个自定义选择器的注释已经很丰富 了,这个类的作用就是:

    优化建议:

    • 未用@componscan注解指定扫描的包时,默认扫描的是@import注解所在的包。

      可以再次添加一个配置文件,在配置文件指定我们需要扫描的包,在代码中加入逻辑:若@component不存在或未指定,则使用配置文件中指定的路径进行扫描。

  • 相关阅读:
    [转] ORACLE 错误编号表一
    基于CkEditor实现.net在线开发之路(1)
    跨行清算系统的实现原理
    应用程序域
    支付机构客户备付金存管办法
    数据库培训二期试题
    MYSQL开发规范
    详解线上线下收单业务(一)第三方支付
    Solr安装配置说明
    进程(Process)
  • 原文地址:https://www.cnblogs.com/heliusKing/p/11774253.html
Copyright © 2011-2022 走看看