SpringBoot快速入门-@ImportSelector注解使用详解

我们上一节演示过@ImportSelector注解的用法,使用非常简单,只需要两个步骤:
1)自定义一个引入类,实现ImportSelector接口,并重写selectImports方法

public class ImportPerson3 implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[]{"com.itzhimei.handle.Person3"};
    }
}

这里返回的就是要加载到ioc的类,可以是一个或多个,指定的类要是类全限定类名,例如:”com.itzhimei.handle.Person3″}。

2)在配置类的@Import中引入自定义类

/**
 * ImportSelector的使用
 */
@Import({ImportPerson3.class})
@Configuration
public class SpringBootConfiguration_5 {

}

如果仅仅是这样使用,其实使用@Configuration通过@Bean来new一个Person3,或者使用@Import直接引入Person3就可以了,没有必要去使用ImportSelector。
但是如果我们要注入的Bean,需要根据一些条件来判断,再决定注入哪个Bean,那么此时ImportSelector的作用就可以发挥出来了。

来看一个例子,比如我们的应用,需要根据不同的操作系统来加载对应操作系统的功能类,此时就需要在Bean注入的时候进行判断了,因为如果你的应用是部署在Linux系统中,应用启动去加载Windows对应的功能类,是没有用处的,还会持续的占用内存资源。
1、定义业务接口

package com.itzhimei.handle.importselector;
/**
 * ImportSelector应用场景Demo
 * 业务接口定义
 */
public interface OSService {

    void doHandler();
}

2、定义业务接口Windows实现类

package com.itzhimei.handle.importselector;
/**
 * ImportSelector应用场景Demo
 * 业务接口Windows实现
 */
public class WindowsOSServiceImpl implements OSService{
    @Override
    public void doHandler() {
        System.out.println("这是Windows业务处理类");
    }
}

3、定义业务接口Linux实现类

package com.itzhimei.handle.importselector;
/**
 * ImportSelector应用场景Demo
 * 业务接口Linux实现
 */
public class LinuxOSServiceImpl implements OSService{
    @Override
    public void doHandler() {
        System.out.println("这是Linux业务处理类");
    }
}

4、定义ImportSelector的实现,基于当前操作系统来加载对应系统的处理类

package com.itzhimei.handle.importselector;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

/**
 * ImportSelector应用场景Demo
 * ImportSelector的实现,基于当前操作系统来加载对应系统的处理类
 */
public class OSServiceImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        String property = System.getProperty("os.name");
        String className;
        if(property.equals("Windows 10")) {
            className = "com.itzhimei.handle.importselector.WindowsOSServiceImpl";
        } else {
            className = "com.itzhimei.handle.importselector.LinuxOSServiceImpl";
        }
        return new String[]{className};
    }
}

/* 输出
com.itzhimei.handle.Person2
com.itzhimei.handle.Person3
Person4
【【【com.itzhimei.handle.importselector.WindowsOSServiceImpl】】】
org.springframework.boot.autoconfigure.AutoConfigurationPackages
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
 */

5、启动SpringBoot项目,查看实际加载的操作系统处理类

/**
 * ImportSelector应用场景Demo
 */
@Import({OSServiceImportSelector.class})
@Configuration
public class SpringBootConfiguration_7 {

}

最后我们启动SpringBoot项目,从启动输出的日志,可以看到实际输出包含这一行:

com.itzhimei.handle.Person2
com.itzhimei.handle.Person3
Person4
【【【com.itzhimei.handle.importselector.WindowsOSServiceImpl】】】
org.springframework.boot.autoconfigure.AutoConfigurationPackages
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration

我们重点标出来的:【【【com.itzhimei.handle.importselector.WindowsOSServiceImpl】】】
也就是我们当前是Windows系统,所以最后加载的是WindowsOSServiceImpl处理类。

我们再看实现接口的重写方法,方法selectImports(AnnotationMetadata annotationMetadata),默认就有一个入参,这是系统传递给我们的,可以使用这个方法的入参获取到@Import标注的Class的各种信息,包括其Class名称,实现的接口名称、父类名称、添加的其它注解等信息,通过这些额外的信息可以根据需要选择需要定义的Bean的Class名称。