@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不存在或未指定,则使用配置文件中指定的路径进行扫描。

原文地址:https://www.cnblogs.com/heliusKing/p/11774253.html

时间: 2024-08-03 10:26:28

@Import导入自定义选择器的相关文章

windows 下Python import 导入自定义模块

周末在家研究这个东西,则找到解决方案. 费话少说,上代码 1 #定义一个自定义的函数,如下 2 #函数的名称必须是字母和数字的组合,不能用数字开头 3 #函数名后用小括号括住入参,可以用逗号分隔多个 4 #如果有返回值用return ,如果没有返回值,默认返回None 5 6 def PanDuanFenShu(score): 7 if 100 >= score >= 90: 8 print("A") 9 if 90 > score >= 80: 10 prin

java 导入自定义类

eclipse导入很容易,昨天上课学了一下用记事本写java,导入自定义类,这就麻烦了. 代码贴一下,方便操作: package tom.jiafei; public class SquareEquation { double a,b,c; double root1,root2; boolean boo; public SquareEquation (double a,double b,double c) { this.a = a; this.b = b; this.c = c; if(a!=0

Python import导入模块

python中的import语句是用来导入模块的,在python模块库中有着大量的模块可供使用,要想使用这些文件需要用import语句把指定模块导入到当前程序中. import语句作用 import语句作用就是用来导入模块的,它可以出现在程序中的任何位置. import语句语法 使用import语句导入模块,import语句语法如下:import module关键字 模块名 使用方法例如:import math       #入导math模块math.floor()        #调用math

Python3导入自定义皇冠体育平台开发模块的3种方式

开始第一种,直接 import 这里有个大前提,就是你的py执行文件和模块同属于同个目录(父级目录),如下图: 01 main.py 和 pwcong模块同在python目录 执行文件为main.py pwcong文件夹为一个模块 我把pwcong模块提供的函数写在 init.py 里,里面只提供一个 hi 函数: # pwcong 模块的 __init__.py # -*- coding: utf-8 -*- def hi(): print("hi") 1 2 3 4 5 执行文件m

import导入模块 【python】

模块的使用:通过import导入模块,然后按照"模块.函数"的格式使用模块的函数. 如: >>> import math >>> math.floor(32.9) 如果不希望每次调用函数的时候都写上模块的名字,可以使用import另外一种形式. 例: >>> from math import sqrt >>> sqrt(9) 使用了"from 模块 import 函数"之后,可以直接使用函数,不

Golang- import 导入包的语法

一 包的导入语法 在写Go代码的时候经常用到import这个命令用来导入包文件,看到的方式参考如下: import( "fmt" ) 然后在代码里面可以通过如下的方式调用 fmt.Println("hello world") 上面这个fmt是Go语言的标准库,他其实是去GOROOT下去加载该模块,当然Go的import还支持如下两种方式来加载自己写的模块: 相对路径     import   "./model"                 /

@import导入外部样式表与link链入外部样式表的区别

昨天碰到同事问了一个问题,@impor导入外部样式与link链入外部样式的优先级是怎样的,为什么实验的结果是按照样式表导入后的位置来决定优先级. 今天就这个问题,度娘上找了很久,终于有个总结性的答案出来了.我感觉这个可信度还是挺高的..如果大家有疑问或其他观点,欢迎一起探讨一下.具体总结如 下: 先解释一下网页添加css样式的方法,一共有四种,分别是: 一.内嵌样式——直接在页面的标签里加<div style="border:1px red solid;">测试信息<

jquery 自定义选择器

//  HTML 代码 <body> <div id="divid1" class="divclass">白色</div> <div id="divid2" class="divclass">白色</div> <div id="divid3" class="divclass">白色</div> <d

jQuery Custom Selector JQuery自定义选择器

什么是JQuery的选择器呢,详见JQuery中的Selector: http://docs.jquery.com/Selectors 比如 $("div:contains('John')").css("text-decoration", "underline");的contains选择器等等 JQuery自定义选择器的基本语法: $.expr[':'].test = function(obj, index, meta, stack){ /* o