Import引入ImportSelector
大约 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);
}
}

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