springboot之BeanDefinitionLoader分析

写在前面

关于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 + "'");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值