Spring boot源码分析-BeanDefinitionLoader(7)
BeanDefinitionLoader用来注册xml或者javaConfig中的bean,是AnnotatedBeanDefinitionReader的一个简单的外观模式,主要做的工作就是注册bean
该类在Springboot主函数准备Context容器的prepareContext的方法中被调用
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
//设置获取
postProcessApplicationContext(context);
//对context进行initializer操作
applyInitializers(context);
//在springboot初始化的时候 没有针对context的Prepared做任何的操作
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
// DefaultListableBeanFactory
// 注册springApplicationArguments的bean 用来存放启动时候的Arguments
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// Load the sources
// 获取启动参数里面的sources 一般就是Configuration的配置类
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
//load就是加载配置的类
load(context, sources.toArray(new Object[sources.size()]));
//容器准备完成 还没有调reflash方法的时候,主要可以对容器设置context.addBeanFactoryPostProcessor(),用于对BeanFactory进行一些设置
listeners.contextLoaded(context);
}
- 首先看这个BeanDefinitionLoader的成员变量,BeanDefinitionLoader持有了各种类型的BeanDefinitionReader,都是用来注册bean用的
class BeanDefinitionLoader {
private final Object[] sources;
private final AnnotatedBeanDefinitionReader annotatedReader;
private final XmlBeanDefinitionReader xmlReader;
private BeanDefinitionReader groovyReader;
private final ClassPathBeanDefinitionScanner scanner;
private ResourceLoader resourceLoader;
}
可以根据各种传入的参数处理,注册bean,有一下三种情况:
1.处理javaConfig,当传入的是一个ChapterProfilesApplication.class的bean的时候,会使用AnnotatedBeanDefinitionReader去处理参数
SpringApplication.run(ChapterProfilesApplication.class, args);
private int load(Class<?> source) {
if (isGroovyPresent()) {
// Any GroovyLoaders added in beans{} DSL can contribute beans here
if (GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source,
GroovyBeanDefinitionSource.class);
load(loader);
}
}
if (isComponent(source)) {
this.annotatedReader.register(source);
return 1;
}
return 0;
}
2.处理Package,当传入的是一个Package的bean的时候,会使用ClassPathBeanDefinitionScanner去处理参数
Package aPackage =Package.getPackage("com.leone.chapter.profiles");
SpringApplication.run(aPackage, args);
private int load(Package source) {
return this.scanner.scan(source.getName());
}
3.处理Resource类型的配置,会使用XmlBeanDefinitionReader去处理注册bean
SpringApplication.run(new ClassPathResource("applicationContext.xml"), args);
private int load(Resource source) {
if (source.getFilename().endsWith(".groovy")) {
if (this.groovyReader == null) {
throw new BeanDefinitionStoreException(
"Cannot load Groovy beans without Groovy on classpath");
}
return this.groovyReader.loadBeanDefinitions(source);
}
return this.xmlReader.loadBeanDefinitions(source);
}
4.处理String类型的配置,会按照class,Resource,Package的顺序尝试去解析String串进行加载
SpringApplication.run("classpath:/applicationContext.xml", args);
private int load(CharSequence source) {
String resolvedSource = this.xmlReader.getEnvironment()
.resolvePlaceholders(source.toString());
// Attempt as a Class
try {
return load(ClassUtils.forName(resolvedSource, null));
}
catch (IllegalArgumentException ex) {
// swallow exception and continue
}
catch (ClassNotFoundException ex) {
// swallow exception and continue
}
// Attempt as resources
Resource[] resources = findResources(resolvedSource);
int loadCount = 0;
boolean atLeastOneResourceExists = false;
for (Resource resource : resources) {
if (isLoadCandidate(resource)) {
atLeastOneResourceExists = true;
loadCount += load(resource);
}
}
if (atLeastOneResourceExists) {
return loadCount;
}
// Attempt as package
Package packageResource = findPackage(resolvedSource);
if (packageResource != null) {
return load(packageResource);
}
throw new IllegalArgumentException("Invalid source '" + resolvedSource + "'");
}