敞开成长之旅!这是我参与「日新方案 12 月更文挑战」的第17天,点击检查活动概况

1、@ComponentScan

1.1 界说

@ComponentScan,是来自Spring结构的一个注解

  • 它的作用是对 指定的package进行扫描,找到其中符合条件的类,默认是搜索被注解@Component修改的装备类
  • 经过特点basePackages或basePackageClasses,来指定要进行扫描的package
  • 如果未指定package,则默认扫描当前@ComponentScan所润饰的类所在的package

1.2 举例

@ComponentScan
public class Application {
}
@ComponentScan(basePackages = {"com.xx.code", "com.yy.code"})
public class Application {
}
@Component(excludeFilters = {
  @ComponentScan.Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
  @ComponentScan.FIlter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)
})
public class Application {
}

2、@Import

2.1 界说

@Import,是来自Spring结构的一个注解

  • 它的作用是提供了一种显式地从其它当地加载装备类的办法,这样能够防止运用性能较差的组件扫描(Component Scan)
  • 支撑导入:
    • 一般类
    • 接口ImportSelector的完成类
    • 接口ImportBeanDefinitionRegistrar的完成类

2.2 导入一般类

能够经过@Import导入一个一般类,效果类似于这个一般类被注解@Component所润饰

public class A {
}
public class ConfigA {
    @Bean
    public A a() {
        return new A();
    }
}
@Configuration
@Import(ConfigA.class)
public class ConfigB {
}
public class Test01Main {
    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB.class);
        // 现在Bean ConfigA 和 A 都在IoC容器中,是可用的
        ConfigA ca = ctx.getBean(ConfigA.class);
        A a = ctx.getBean(A.class);
        System.out.println(ca.getClass().getSimpleName());
        System.out.println(a.getClass().getSimpleName());
    }
}

2.3 注解@Import导入接口ImportSelector完成类

能够经过@Import导入一个接口ImportSelector完成类。接口ImportSelector中有一个selectImports办法,它的返回值是一个字符串数组,数组中的每个元素分别代表一个将被导入的装备类的全限定名。运用该特性咱们能够给IoC容器动态地导入多个装备类。

public class Tiger {
}
public class ZooConfig {
    @Bean
    public Tiger tiger() {
        return new Tiger();
    }
}
public class ZooImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[] {"com.example.springboot_12.test02.ZooConfig"};
    }
}
@Configuration
@Import({ZooImportSelector.class})
public class ConfigB02 {
}
public class Test02Main {
    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB.class);
        // 现在Bean ZooConfig 和 Tiger 都在IoC容器中,是可用的
        ZooConfig zc = ctx.getBean(ZooConfig.class);
        Tiger t = ctx.getBean(Tiger.class);
        System.out.println(zc.getClass().getSimpleName());
        System.out.println(t.getClass().getSimpleName());
    }
}

2.4 注解@import导入接口ImportBeanDefinitionRegistrar完成类

能够经过@Import导入一个接口ImportBeanDefinitionRegistrar的完成类。经过它,咱们能够手动将多个BeanDefinition注册到IoC容器中,然后完成个性化的定制。运用该特性咱们能够给IoC容器动态地导入多个BeanDefinition。

public class Dog {
}
public class ZooRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata am, BeanDefinitionRegistry bdr) {
        GenericBeanDefinition gbd = new GenericBeanDefinition();
        gbd.setBeanClass(Dog.class);
        bdr.registerBeanDefinition("dog", gbd);
    }
}
@Configuration
@Import({ZooRegistrar.class})
public class ConfigB03 {
}
public class Test03Main {
    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB03.class);
        // 现在Bean Dog 在IoC容器中,是可用的
        Dog d = ctx.getBean("dog", Dog.class);
        System.out.println(d.getClass().getSimpleName());
    }
}

3、总结

总结SpringBoot加载装备类的办法

  1. 运用注解 @ComponentScan
  2. 运用注解@Import
    1. 导入一般类
    2. 导入选择器 ImportSelector
    3. 导入注册器 ImpotBeanDefinitionRegistrar

应该运用哪种办法来加载SpringBoot的主动装备类呢?

首先扫除注解@ComponentScan。由于运用它很不方便,开发人员需求记住每个第三方jar包中的package名称,然后把它们写到应用程序中,这不符合开箱即用。

@Import更不能运用了,它还需求开发人员记住第三方jar包中的具体类名。

运用@Import导入一个BeanDefinition注册器,也不恰当,BeanDefinition注册器的设计方针是对@Bean办法的一个补充,它针对的是BeanDefinition层面的,并不是用来导入装备类的。

运用@Import导入一个选择器ImportSelector,它十分合适用来完成主动装备。 SpringBoot运用注解@Import 导入一个ImportSelector然后完成了主动装备的功能。