Spring Boot源码简析(二)
load 资源过程
在上一篇博客中我们说了SpringApplication的主要启动逻辑,其中context创建之后第一步就是执行
load(context, sources.toArray(new Object[sources.size()]));
load主要就是把我们传入的资源生成相应的BeanDefinition。
protected void load(ApplicationContext context, Object[] sources) {
//创建一个BeanDefinitionLoader,看名字就知道使用来加载Bean信息的
BeanDefinitionLoader loader = createBeanDefinitionLoader(
getBeanDefinitionRegistry(context), sources);
//塞一个beanNameGenerator
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
//塞一个resourceLoader,用来先加载资源然后再解析
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
//开始加载
loader.load();
}
这里主要是先创建了一个BeanDefinitionLoader并在加载前做了一些准备工作,然后执行加载操作。
public int load() {
int count = 0;
for (Object source : this.sources) {
count += load(source);
}
return count;
}
private int load(Object source) {
Assert.notNull(source, "Source must not be null");
if (source instanceof Class<?>) {
return load((Class<?>) source);
}
if (source instanceof Resource) {
return load((Resource) source);
}
if (source instanceof Package) {
return load((Package) source);
}
if (source instanceof CharSequence) {
return load((CharSequence) source);
}
throw new IllegalArgumentException("Invalid source type " + source.getClass());
}
此处是根据传入的资源类型来加载资源,下面根据具体的资源类型来查看资源加载资源
Load class
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);
}
}
//查看元素是否有@Component注解
if (isComponent(source)) {
//将source对应的类型注册一个beanDefinition
this.annotatedReader.register(source);
return 1;
}
return 0;
}
这里就是将我们传入的类创建对应的beanDefinition并注册到registry中去。
Load resource
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);
}
//调用xmlReader来加载beanDefinition
return this.xmlReader.loadBeanDefinitions(source);
}
这里可以很明显看到,通过资源加载其实也就是我们平时使用xml配置,springboot是可以支持像spring一样的通过配置文件配置bean的方式。
Load package
private int load(Package source) {
//调用扫描器来扫描package下所有类文件
return this.scanner.scan(source.getName());
}
这里是我比较感兴趣的地方,因为在spring没有配置文件的情况下,主要的bean加载的方式就应该是通过这个方法实现
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
//遍历所有的包
for (String basePackage : basePackages) {
Set<BeanDefinition> candidates =
//扫描该包下的所有文件,包含componet注解的类将会创建对应的BeanDefinition
findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
//获取bean的scope信息,主要是是否是singleton、是否需要代理
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
//创建beanName
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
总体来说,load的操作就是把用户传入的各种资源对应的bean的beanDefinition信息到注册中心。