@import
我们可以用这个注解导入bean到容器里面。
3个方式
直接@import
导入的baen
@Data
public class User {
private Integer id;
private String name;
}
导入方法:
@Configuration
@Import(value = { User.class })
public class Config {
}
通过ImportBeanDefinitionRegistrar
还是上面的bean。但是 不是直接导入。
public class UserServiceBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
BeanDefinitionBuilder user = BeanDefinitionBuilder.rootBeanDefinition(User.class);
// 通过registry就可以注入到容器里啦
registry.registerBeanDefinition("user", user.getBeanDefinition());
}
}
注解方法:
@Configuration
@Import(value = { UserServiceBeanDefinitionRegistrar.class })
public class Config {
}
通过ImportSelector
public class UserServiceImportSelect implements ImportSelector {
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[] { User.class.getName() };
}
}
注解方法:
@Configuration
@Import(value = { UserServiceImportSelect.class })
public class Config {
}
小结
上述3个方法都可以将bean导入到springbean容器里面。
源码分析
老规矩,我们从springboot的启动开始分析,虽然这直接属于spring那一块。我们从run开始点点点,进入下面方法。
public ConfigurableApplicationContext run(String... args) {
......
refreshContext(context);
......
}
直接关注这个方法,这个方法会调用核心,他是spring容器启动的核心方法。
然后不断点点,进入到这个核心方法。
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
.....
invokeBeanFactoryPostProcessors(beanFactory);
.....
}
这个方法提取出invokeBeanFactoryPostProcessors方法,点进去。
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
......
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
......
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
......
}
进入这个方法后主要有2个方法需要注意。这个接口BeanFactoryPostProcessor的实现类是这个ConfigurationClassPostProcessor。进入invokeBeanFactoryPostProcessors方法。
private static void invokeBeanFactoryPostProcessors(
Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
for (BeanFactoryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanFactory(beanFactory);
}
}
调用了postProcessBeanFactory方法。然后点点点,进入processConfigBeanDefinitions方法,这个就是处理@import的方法了。
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
......
parser.parse(candidates);
......
}
进入这个方法,不断进入doProcessConfigurationClass这个方法里面。
@Nullable
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
......
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), true);
......
}
进去后,第一个方法获取到本项目下所有的bean,然后过滤找到是@Import的bean,再然后在processImports方法里面将其里面的bean注入spring容器进去。