Import引入ImportSelector

HeJin大约 2 分钟源码解析bean的注入

定义3个需要导入的bean,与主启动类不在同一个包,避免SpringBoot的自动扫包干扰结果。

@Service
public class AdminService {
}
public class GroupService {
}
public class UserService {
}

基本使用

实现ImportSelector接口:

public class SimpleImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.service.AdminService", 
                "com.service.GroupService", "com.service.UserService"};
    }

    @Override
    public Predicate<String> getExclusionFilter() {
        return ImportSelector.super.getExclusionFilter();
    }
}
  • 第一个方法返回需要导入的bean的全路径类名。这里我们把定义的三个类都导入。
  • 第二个方法是不需要导入的bean,需要进行过滤判断的。保持默认。

修改主启动类:

@SpringBootApplication
@Import(SimpleImportSelector.class)
public class SpringBootAnalysisApp {
    private static final Logger logger = LoggerFactory.getLogger(SpringBootAnalysisApp.class);

    public static void main(String[] args) {
        ApplicationContext applicationContext = SpringApplication.run(SpringBootAnalysisApp.class, args);
        AdminService adminService = applicationContext.getBean(AdminService.class);
        logger.info("adminService: {}", adminService);
        GroupService groupService = applicationContext.getBean(GroupService.class);
        logger.info("adminService: {}", groupService);
        UserService userService = applicationContext.getBean(UserService.class);
        logger.info("userService: {}", userService);
    }
}

结果:

com.sanfen.SpringBootAnalysisApp         : adminService: com.service.AdminService@f973499
com.sanfen.SpringBootAnalysisApp         : adminService: com.service.GroupService@37c5fc56
com.sanfen.SpringBootAnalysisApp         : userService: com.service.UserService@1c025cb

发现三个service类都被加入到Spring容器了。但这里就有问题了,全路径类名我们是写死的。以后需要修改,就要修改源码。不方便也不好用。要是可以直接把全类名写到配置文件中就好了。接下来试试看。

进阶使用

把需要注册到容器的类的全类名,写到配置文件中。这样需要修改的时候,只改变配置文件就行了。

MyImportSelector:在ImportSelector实现类中,我们从配置文件读取全类名,并且过滤了com.service.AdminService,这样AdminService类就不会被导入了。

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        // 读取配置文件
        ResourceBundle bundle = ResourceBundle.getBundle("import");
        String className = bundle.getString("className");
        // 转换成字符串数组返回
        String[] res = className.split(",");
        System.out.println(Arrays.toString(res));

        return res;
    }

    @Override
    public Predicate<String> getExclusionFilter() {
        return s -> s.contains("com.service.AdminService");
    }
}

import.properties配置文件:

className=com.service.UserService,\
  com.service.AdminService,\
  com.service.GroupService

主启动类导入MyImportSelector:

@SpringBootApplication
@Import(MyImportSelector.class)
public class SpringBootAnalysisApp {
    private static final Logger logger = LoggerFactory.getLogger(SpringBootAnalysisApp.class);

    public static void main(String[] args) {
        ApplicationContext applicationContext = SpringApplication.run(SpringBootAnalysisApp.class, args);
        GroupService groupService = applicationContext.getBean(GroupService.class);
        logger.info("adminService: {}", groupService);
        UserService userService = applicationContext.getBean(UserService.class);
        logger.info("userService: {}", userService);
        AdminService adminService = applicationContext.getBean(AdminService.class);
        logger.info("adminService: {}", adminService);
    }
}
image-20221231160329644
image-20221231160329644

可以发现,控制台输出了从配置文件读取到的三个全类名。因为我们使用排除过滤器过滤掉了AdminService,所以没有找到对应的bean。