Springboot-importSelector

  • Post author:
  • Post category:其他


ImportSelector接口概述

ImportSelector接口是至spring中导入外部配置的核心接口,在SpringBoot的自动化配置和@EnableXXX(功能性注解)都有它的存在。我们先来看一下ImportSelector接口的源码,如下所示。

public interface ImportSelector {

	/**
	 * Select and return the names of which class(es) should be imported based on
	 * the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
	 * @return the class names, or an empty array if none
	 */
	String[] selectImports(AnnotationMetadata importingClassMetadata);

	/**
	 * Return a predicate for excluding classes from the import candidates, to be
	 * transitively applied to all classes found through this selector's imports.
	 * <p>If this predicate returns {@code true} for a given fully-qualified
	 * class name, said class will not be considered as an imported configuration
	 * class, bypassing class file loading as well as metadata introspection.
	 * @return the filter predicate for fully-qualified candidate class names
	 * of transitively imported configuration classes, or {@code null} if none
	 * @since 5.2.4
	 */
	@Nullable
	default Predicate<String> getExclusionFilter() {
		return null;
	}

}

该接口文档上说的明明白白,其主要作用是收集需要导入的配置类,selectImports()方法的返回值就是我们向Spring容器中导入的类的全类名。如果该接口的实现类同时实现EnvironmentAware, BeanFactoryAware ,BeanClassLoaderAware或者ResourceLoaderAware,那么在调用其selectImports方法之前先调用上述接口中对应的方法,如果需要在所有的@Configuration处理完在导入时可以实现DeferredImportSelector接口。

在ImportSelector接口的selectImports()方法中,存在一个AnnotationMetadata类型的参数,这个参数能够获取到当前标注@Import注解的类的所有注解信息。

ImportSelector接口实例

首先,我们创建一个MySelector类实现ImportSelector接口,如下所示。

/**
 * @import 注解中使用ImportSelector
 * 自定义逻辑,返回需要导入的组件
 */
public class MySelector implements ImportSelector {
    /**
     * 返回值为需要导入到容器中的bean的全类名数组
     * @param annotationMetadata
     * @return
     */
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        Map<String, Object> attributes = annotationMetadata.getAnnotationAttributes(MyScan.class.getName());
        if (CollectionUtils.isEmpty(attributes)) {
            return new String[0];
        }
        String[] basePackages = (String[]) attributes.get("basePackages");

        ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
        scanner.addIncludeFilter(new AssignableTypeFilter(Student.class));//这里实现包含,相当@ComponentScan  includeFilters
        scanner.addIncludeFilter(new AssignableTypeFilter(User.class));
        //scanner.addExcludeFilter(new AssignableTypeFilter(Object.class));//这里可以实现排除,相当@ComponentScan  excludeFilters

        Set<String> classs = new HashSet<>();
        for (String basePackage : basePackages) {
            Set<BeanDefinition> components = scanner.findCandidateComponents(basePackage);
            components.forEach(bean -> classs.add(bean.getBeanClassName()));
        }
        return classs.toArray(new String[0]);
    }
}

Student

public class Student {

    private String name;

    public Student() {
        this.name = "初始化数据";
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                '}';
    }
}

User:

@TableName(value = "user")
public class User extends BaseEntity{
    @TableField(value = "name")
    private String name;
    @TableField(value = "sex")
    private Integer sex;

}

上面已经把Student、User全类名返回到MySelector类的selectImports()方法中。

运行启动类,我们会发现这两个类已经加载进Spring容器。



版权声明:本文为jinwufeiyang原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。