写在前面
关于springboot系列详细分析,可以参考这里。
在这篇文章中分析了springboot启动的详细过程,其中涉及到了bean定义的加载,但是并没有详细讲解这个过程,本文一起来看下。
1:分析
方法org.springframework.boot.SpringApplication#run(java.lang.String...)
,源码如下:
org.springframework.boot.SpringApplication#run(java.lang.String...)
public ConfigurableApplicationContext run(String... args) {
...snip...
try {
...snip...
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
...snip...
}
catch (Throwable ex) {
...snip...
}
...snip...
return context;
}
继续:
org.springframework.boot.SpringApplication#prepareContext
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
...snip...
// 启动类的class,我这里是
// ["class com.example.springbootintegarationspringmvc.SpringbootIntegrationSpringmvcApplication"]
// 该处源码如下:
/*
org.springframework.boot.SpringApplication#getAllSources
public Set<Object> getAllSources() {
Set<Object> allSources = new LinkedHashSet<>();
if (!CollectionUtils.isEmpty(this.primarySources)) {
allSources.addAll(this.primarySources);
}
if (!CollectionUtils.isEmpty(this.sources)) {
allSources.addAll(this.sources);
}
return Collections.unmodifiableSet(allSources);
}
*/
Set<Object> sources = getAllSources();
// <202106281455>
load(context, sources.toArray(new Object[0]));
...snip...
}
<202106281455>
处源码如下:
org.springframework.boot.SpringApplication#load
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
// <202106281506>
// 创建bean定义加载器
BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
// <202106281543>
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
// <202106281549>
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
// <202106281551>
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
// <202106281553>
loader.load();
}
<202106281506>
处是创建bean定义加载器,具体参考1.1:createBeanDefinitionLoader
。<202106281543>
处是设置bean名称生成器,源码如下:
org.springframework.boot.BeanDefinitionLoader#setBeanNameGenerator
// 设置底层读取器,扫描器使用的bean名称生成器
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
this.annotatedReader.setBeanNameGenerator(beanNameGenerator);
this.xmlReader.setBeanNameGenerator(beanNameGenerator);
this.scanner.setBeanNameGenerator(beanNameGenerator);
}
<202106281549>
处是设置用于加载资源的资源加载器,源码如下:
org.springframework.boot.BeanDefinitionLoader#setResourceLoader
public void setResourceLoader(ResourceLoader resourceLoader) {
// 赋值到全局变量
this.resourceLoader = resourceLoader;
// 设置资源加载器到读取器
this.xmlReader.setResourceLoader(resourceLoader);
// 设置资源加载器到扫描器
this.scanner.setResourceLoader(resourceLoader);
}
<202106281551>
处源码如下:
org.springframework.boot.BeanDefinitionLoader#setEnvironment
// 设置底层读取器和扫描器使用的环境对象
public void setEnvironment(ConfigurableEnvironment environment) {
this.annotatedReader.setEnvironment(environment);
this.xmlReader.setEnvironment(environment);
this.scanner.setEnvironment(environment);
}
<202106281553>
处是执行具体的加载,具体参考2:load
。
1.1:createBeanDefinitionLoader
源码如下:
org.springframework.boot.SpringApplication#createBeanDefinitionLoader
// 创建BeanDefintionLoader的工厂方法
protected BeanDefinitionLoader createBeanDefinitionLoader(BeanDefinitionRegistry registry, Object[] sources) {
// <202106281509>
return new BeanDefinitionLoader(registry, sources);
}
<202106281509>
处源码如下:
org.springframework.boot.BeanDefinitionLoader#BeanDefinitionLoader
// registry:注册bean定义的bean定义注册器
// sources:需要加载为bean定义的资源
BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
Assert.notNull(registry, "Registry must not be null");
Assert.notEmpty(sources, "Sources must not be empty");
// 赋值到全局变量
this.sources = sources;
// 基于注解的bean定义读取器
this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
// 基于xml的bean定义读取器
this.xmlReader = new XmlBeanDefinitionReader(registry);
// 是否使用groovy,源码如下:
/*
org.springframework.boot.BeanDefinitionLoader#isGroovyPresent
private boolean isGroovyPresent() {
return ClassUtils.isPresent("groovy.lang.MetaClass", null);
}
*/
if (isGroovyPresent()) {
this.groovyReader = new GroovyBeanDefinitionReader(registry);
}
// bean定义扫描器
this.scanner = new ClassPathBeanDefinitionScanner(registry);
// 设置排除,防止重复扫描
this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
}
2:load
源码如下:
org.springframework.boot.BeanDefinitionLoader#load()
public int load() {
int count = 0;
for (Object source : this.sources) {
// <202106281603>
count += load(source);
}
return count;
}
<202106281603>
处源码如下:
org.springframework.boot.BeanDefinitionLoader#load(java.lang.Object)
private int load(Object source) {
Assert.notNull(source, "Source must not be null");
// <202106281606>
if (source instanceof Class<?>) {
return load((Class<?>) source);
}
// <202106281607>
if (source instanceof Resource) {
return load((Resource) source);
}
// <202106281608>
if (source instanceof Package) {
return load((Package) source);
}
// <202106281609>
if (source instanceof CharSequence) {
return load((CharSequence) source);
}
throw new IllegalArgumentException("Invalid source type " + source.getClass());
}
<202106281606>
处参考2.1:加载class资源为bean定义
。<202106281607>
处参考2.2:加载Resource为bean定义
。<202106281608>
处如果是包路径的话,执行的加载,具体参考2.3:加载Package为bean定义
,<202106281609>
处如果是字符串路径,具体参考加载CharSequence为bean定义
。
2.1:加载class为bean定义
源码如下:
org.springframework.boot.BeanDefinitionLoader#load(java.lang.Class<?>)
private int load(Class<?> source) {
// 忽略
if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
load(loader);
}
// <202106281646>
if (isComponent(source)) {
// 执行注册,spring的内容了,此处不深究
this.annotatedReader.register(source);
return 1;
}
return 0;
}
<202106281646>
处源码如下:
org.springframework.boot.BeanDefinitionLoader#isComponent
private boolean isComponent(Class<?> type) {
// 如果是有@Component注解(如@Configuration注解也是为true,因为组合了@Component注解)
if (AnnotationUtils.findAnnotation(type, Component.class) != null) {
return true;
}
// 忽略
if (type.getName().matches(".*\\$_.*closure.*") || type.isAnonymousClass() || type.getConstructors() == null
|| type.getConstructors().length == 0) {
return false;
}
// 默认返回true
return true;
}
2.2:加载Resource为bean定义
源码如下:
org.springframework.boot.BeanDefinitionLoader#load(org.springframework.core.io.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);
}
// 执行bean定义的加载,此处是spring的内容了,不深究
return this.xmlReader.loadBeanDefinitions(source);
}
2.3:加载Package为bean定义
源码如下:
org.springframework.boot.BeanDefinitionLoader#load(java.lang.Package)
private int load(Package source) {
// 执行bean定义的加载,此处是spring的内容了,不深究
return this.scanner.scan(source.getName());
}
2.4:加载CharSequence为bean定义
源码如下:
// 按照Class(source是类全限定名) > Resource(source是xml配置文件路径) > Package的情况依次尝试加载(source是包路径)
private int load(CharSequence source) {
// 处理可能存在的占位符
String resolvedSource = this.xmlReader.getEnvironment().resolvePlaceholders(source.toString());
try {
// 尝试class加载
return load(ClassUtils.forName(resolvedSource, null));
}
catch (IllegalArgumentException | ClassNotFoundException ex) {
// 发生异常,这里什么也不做,继续后续
}
// 尝试Resource假记载
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;
}
// 尝试Package加载
Package packageResource = findPackage(resolvedSource);
if (packageResource != null) {
return load(packageResource);
}
throw new IllegalArgumentException("Invalid source '" + resolvedSource + "'");
}