栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring 5.x源码剖析-带你Beandefinition是如何生成的!(万字长文)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring 5.x源码剖析-带你Beandefinition是如何生成的!(万字长文)

文章目录
  • 前言
    • BeanFactory
    • BeanDefinition
  • 1. prepareRefresh()
  • 2. obtainFreshBeanFactory()
    • `loadBeanDefinitions(beanFactory)`
    • `loadBeanDefinitions(beanDefinitionReader)`
    • `reader.loadBeanDefinitions(configLocations)`
    • `loadBeanDefinitions(location)`
    • `loadBeanDefinitions(resources)`
    • `doLoadBeanDefinitions(inputSource, resource())`
    • `registerBeanDefinitions(doc, createReaderContext(resource))`
    • `parseBeanDefinitions(root, this.delegate)`
    • `processBeanDefinition(ele, delegate)`
    • `parseBeanDefinitionElement(ele)`
    • `registerBeanDefinition(bdHolder, getReaderContext().getRegistry())`
  • 总结

源码阅读传送门

  1. Spring IOC容器初始化源码剖析(一)
前言

上一章我们了解了IOC容器的相关概念、如何通过代码实例化容器以及容器初始化的核心方法refresh(),本章开始初探refresh(),在阅读源码前,我们有必要先了解什么是BeanFactory以及BeanDefinition,这将有利于我们对接来下源码的理解。

BeanFactory

BeanFactory顾名思义,Bean的工厂,用于创建与管理Bean。

从上图我们可以看到ApplicationContext继承了两个BeanFactory的子接口:

  • ListableBeanFactory:listable(可列举的),BeanFactory只能获取单个Bean,ListableBeanFactory可以获取多个Bean。
  • HierarchicalBeanFactory:hierarchical(分层),可以通过配置的方式设置父类的bean工厂。
BeanDefinition

Spring IOC容器管理一个或多个Bean,这些bean使用提供给容器的配置元数据创建的(例如通过xml定义的形式)。在容器本身,这些Bean表示为BeanDefinition对象。

BeanDefinition主要包含哪些信息呢?

  1. 包限定名,通常是定义bean的具体实现类。
  2. bean行为配置元素,比如:范围、生命周期回调等。
  3. 对bean执行工作所需的其它bean引用(依赖)。
  4. 要在新创建对象中设置的其它配置,比如数据库连接池bean的连接数大小等。

源码如下:

public interface BeanDefinition extends AttributeAccessor, BeanmetadataElement {

	
	String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

	
	String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

	
	int ROLE_APPLICATION = 0;

	
	int ROLE_SUPPORT = 1;

	
	int ROLE_INFRASTRUCTURE = 2;
	
	// Modifiable attributes

	
	void setParentName(@Nullable String parentName);

	
	@Nullable
	String getParentName();

	
	void setBeanClassName(@Nullable String beanClassName);

	
	@Nullable
	String getBeanClassName();

	
	void setScope(@Nullable String scope);

	
	@Nullable
	String getScope();

	
	void setLazyInit(boolean lazyInit);

	
	boolean isLazyInit();

	
	void setDependsOn(@Nullable String... dependsOn);

	
	@Nullable
	String[] getDependsOn();

	
	void setAutowireCandidate(boolean autowireCandidate);

	
	boolean isAutowireCandidate();

	
	void setPrimary(boolean primary);

	
	boolean isPrimary();

	
	void setFactoryBeanName(@Nullable String factoryBeanName);

	
	@Nullable
	String getFactoryBeanName();

	
	void setFactoryMethodName(@Nullable String factoryMethodName);

	
	@Nullable
	String getFactoryMethodName();

	
	ConstructorArgumentValues getConstructorArgumentValues();

	
	default boolean hasConstructorArgumentValues() {
		return !getConstructorArgumentValues().isEmpty();
	}

	
	MutablePropertyValues getPropertyValues();

	
	default boolean hasPropertyValues() {
		return !getPropertyValues().isEmpty();
	}

	
	void setInitMethodName(@Nullable String initMethodName);

	
	@Nullable
	String getInitMethodName();

	
	void setDestroyMethodName(@Nullable String destroyMethodName);

	
	@Nullable
	String getDestroyMethodName();

	
	void setRole(int role);

	
	int getRole();

	
	void setDescription(@Nullable String description);

	
	@Nullable
	String getDescription();


	// Read-only attributes

	
	ResolvableType getResolvableType();

	
	boolean isSingleton();

	
	boolean isPrototype();

	
	boolean isAbstract();

	
	@Nullable
	String getResourceDescription();

	
	@Nullable
	BeanDefinition getOriginatingBeanDefinition();

}
1. prepareRefresh()

prepareRefresh()是refresh()的第一个方法,prepareRefresh()主要用于设置启动开始时间、活动标志位、初始化环境配置参数、校验参数等,来为初始化做好准备。

// AbstractApplicationContext#prepareRefresh()
protected void prepareRefresh() {
	// 记录当前时间戳,切换活动状态
	this.startupDate = System.currentTimeMillis();
	this.closed.set(false);
	this.active.set(true);

	// 部分省略日志打印

	// 初始化环境配置参数
	// 当前类方法本身do nothing,
	// 通过重写初始化环境属性信息。
	initPropertySources();

	// 获取initPropertySources中初始化的环境配置参数,
	// 来进行验证标记为required的属性
	getEnvironment().validateRequiredProperties();

	// 载入预刷新应用程序监听
	if (this.earlyApplicationListeners == null) {
		this.earlyApplicationListeners = new linkedHashSet<>(this.applicationListeners);
	}
	else {
		// 将本地应用程序监听器重置为预刷新状态。
		this.applicationListeners.clear();
		this.applicationListeners.addAll(this.earlyApplicationListeners);
	}

	// 允许早期应用事件收集,
	// 当multicaster可用就会发布
	this.earlyApplicationEvents = new linkedHashSet<>();
}
// AbstractApplicationContext#initPropertySources
protected void initPropertySources() {
	// For subclasses: do nothing by default.
}
// AbstractPropertyResolver#validateRequiredProperties
@Override
public void validateRequiredProperties() {
	MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();
	for (String key : this.requiredProperties) {
		// 判断必需的环境配置参数是否为空
		if (this.getProperty(key) == null) {
			ex.addMissingRequiredProperty(key);
		}
	}
	if (!ex.getMissingRequiredProperties().isEmpty()) {
		throw ex;
	}
}

prepareRefresh()大致流程如下:

  1. 记录当前时间戳并设置活动状态。
  2. 初始环境配置参数,校验必需的配置参数。(校验未通过则抛出MissingRequiredPropertiesException: The following properties were declared as required but could not be resolved: [缺失的配置参数数组])
  3. 初始化或清除并载入应用程序监听(ApplicationListener)。
  4. 初始化事件(ApplicationEvent)。
2. obtainFreshBeanFactory()

obtain(获得)fresh(最新的)BeanFactory,该方法中会解析配置元数据,生成BeanDefinition,并注册到BeanFactory中。

该方法链路比较长,最好结合源码一起看,接下来进入正题。

//AbstractApplicationContext#ConfigurableListableBeanFactory()
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
	// 配置加载
	refreshBeanFactory();
	// 获取BeanFactory并返回
	return getBeanFactory();
}
// AbstractRefreshableApplicationContext#refreshBeanFactory()
@Override
protected final void refreshBeanFactory() throws BeansException {
	// 判断BeanFactory是否已经创建
	if (hasBeanFactory()) {
		// 销毁所有已创建的bean
		destroyBeans();
		// 将BeanFactory置空
		closeBeanFactory();
	}
	try {
		// 默认实现创建DefaultListableBeanFactory,
		// 并将容器的父级内部bean工厂作为父bean工厂
		DefaultListableBeanFactory beanFactory = createBeanFactory();
		beanFactory.setSerializationId(getId());
		// 1.设置是否允许覆盖同名bean定义,自动替换前一个定义。
		// 2.设置是否允许bean之间循环引用。
		customizeBeanFactory(beanFactory);
		// 加载配置转换为BeanDefinition注册到beanFactory
		loadBeanDefinitions(beanFactory);
		this.beanFactory = beanFactory;
	}
	catch (IOException ex) {
		throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
	}
}

通过如上refreshBeanFactory()源码,我们可以了解到大致流程:

  1. 判断BeanFactory是否已经创建,若已经创建则销毁所有已创建的bean、并把beanFactory置空。

    // AbstractRefreshableApplicationContext#hasBeanFactory()
    protected final boolean hasBeanFactory() {
    	return (this.beanFactory != null);
    }
    
  2. 创建DefaultListableBeanFactory(该类为BeanFactory的一个默认实现),并将其设置为容器的parentBeanFactory。

  3. customizeBeanFactory()设置是否允许覆盖bean定义及bean之间的循环引用。

    // AbstractRefreshableApplicationContext#customizeBeanFactory
    protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
    	// 设置是否允许同名bean定义覆盖,true:自动替换前一个定义。
    	if (this.allowBeanDefinitionOverriding != null) {
    		beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
    	}
    	// 设置是否允许bean之间循环引用。
    	if (this.allowCircularReferences != null) {
    		beanFactory.setAllowCircularReferences(this.allowCircularReferences);
    	}
    }
    
  4. loadBeanDefinitions(beanFactory)读取配置元数据转换为BeanDefinition注册到beanFactory。

IOC容器管理了一个或多个Bean。在容器本身,这些bean表示为BeanDefinition对象,容器启动过程中,会将Bean解析为BeanDefinition注册到beanFactory中。

loadBeanDefinitions(beanFactory)

开始套娃···

// AbstractXmlApplicationContext#loadBeanDefinitions
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
	XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
	// 配置beanDefinitionReader与context在同一环境中
	beanDefinitionReader.setEnvironment(this.getEnvironment());
	// 使用当前上下文对象作为beanDefinitionReader的ResourceLoader
	beanDefinitionReader.setResourceLoader(this);
	// 设置用于解析的SAX实体解析器,比如解析dtd、xsd文件
	beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
	// 初始化beanDefinitionReader
	// 默认开启XML验证
	initBeanDefinitionReader(beanDefinitionReader);
	// 通过beanDefinitionReader加载BeanDefinition
	// 加载配置转换为BeanDefinition注册到beanFactory
	loadBeanDefinitions(beanDefinitionReader);
}

loadBeanDefinitions(beanFactory)大致步骤:

  1. 实例化XmlBeanDefinitionReader(读取通过Xml文件中配置Bean定义的工具类)、属性配置。
  2. 加载配置转换为BeanDefinition注册到beanFactory。
loadBeanDefinitions(beanDefinitionReader)
// AbstractXmlApplicationContext#loadBeanDefinitions
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
	// 可以通过子类重写getConfigResources的方式指定配置文件数组,
	// getConfigResources()默认返回null
	Resource[] configResources = getConfigResources();
	if (configResources != null) {
		// 从指定配置资源中加载Bean
		reader.loadBeanDefinitions(configResources);
	}
	// 获取本地配置文件
	String[] configLocations = getConfigLocations();
	if (configLocations != null) {
		// 从指定配置文件中加载Bean
		reader.loadBeanDefinitions(configLocations);
	}
}

loadBeanDefinitions(beanDefinitionReader)大致步骤如下:

  1. 在子类重写getConfigResources()方法的前提下,通过重写方法指定逻辑获取配置文件数组(默认返回null),从指定配置文件中加载Bean。
    // AbstractXmlApplicationContext#getConfigResources
    @Nullable
    protected Resource[] getConfigResources() {
    	return null;
    }
    
  2. 获取本地配置文件,从指定配置文件中解析并加载Bean。
reader.loadBeanDefinitions(configLocations)
// AbstractBeanDefinitionReader#loadBeanDefinitions
// 返回所有注册BeanDefinition的个数
@Override
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
	Assert.notNull(locations, "Location array must not be null");
	int count = 0;
	for (String location : locations) {
		count += loadBeanDefinitions(location);
	}
	return count;
}

继续朝下追踪loadBeanDefinitions(location)的内部处理逻辑。

loadBeanDefinitions(location)
// AbstractBeanDefinitionReader#loadBeanDefinitions
@Override
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
	return loadBeanDefinitions(location, null);
}
// AbstractBeanDefinitionReader#loadBeanDefinitions
 
public int loadBeanDefinitions(String location, @Nullable Set actualResources) throws BeanDefinitionStoreException {
	// 获取资源加载器
	ResourceLoader resourceLoader = getResourceLoader();
	// 部分省略
	if (resourceLoader instanceof ResourcePatternResolver) {
		try {
			// 使用资源解析器根据资源文件路径解析并加载
			Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
			// 解析当前资源中的bean定义,
			// 并返回注册BeanDefinition个数
			int count = loadBeanDefinitions(resources);
			// 若actualResources不为null,则把文件资源添加到集合中
			if (actualResources != null) {
				Collections.addAll(actualResources, resources);
			}
			// 部分省略
			// 返回注册个数
			return count;
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", ex);
		}
	}
	else {
		Resource resource = resourceLoader.getResource(location);
		int count = loadBeanDefinitions(resource);
		if (actualResources != null) {
			actualResources.add(resource);
		}
		// 部分省略
		return count;
	}
}

loadBeanDefinitions(location, null)大致流程如下:

  1. getResourceLoader()获得资源加载器。

    @Override
    @Nullable
    public ResourceLoader getResourceLoader() {
    	// this.resourceLoader即AbstractXmlApplicationContext。
    	// 前面源码中有讲解,
    	// 没有印象的可以再去回顾AbstractXmlApplicationContext#loadBeanDefinitions
    	return this.resourceLoader;
    }
    
  2. loader instanceof ResourcePatternResolver = true

  3. 通过资源解析器根据资源文件路径解析并加载(该节点以下的源码,感兴趣可以看看,不感兴趣可以直接跳过)。

    // PathMatchingResourcePatternResolver#getResources
    // 根据指定配置文件路径获取文件资源数组
    @Override
    public Resource[] getResources(String locationPattern) throws IOException {
    	// 部分省略
    	// 判断文件路径是否以‘classpath*’开头
    	// CLASSPATH_ALL_URL_PREFIX:classpath*:
    	// “classpath*:”代表:该工程有多个classpath,同时寻找并加载多个classpath路径下的文件
    	// “classpath:” 代表: 与上反之
    	if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
    		// 判断截取“classpath*:”后的文件路径是否包含“*”或“?”或“{”或“}”
    		// 例如:配置为:“classpath*:config") + 1 :
    				locationPattern.indexOf(':') + 1);
    		// 判断是否包含特殊字符
    		if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
    			return findPathMatchingResources(locationPattern);
    		}
    		else {
    			// 单文件根据名称加载
    			// 我们的demo中直接走这个分支
    			return new Resource[] {getResourceLoader().getResource(locationPattern)};
    		}
    	}
    }
    

    具体查找文件的方法就不继续延伸了,有兴趣的可以展开阅读。

  4. loadBeanDefinitions(resources)解析资源所有的bean定义,并返回注册成功BeanDefinition个数。

我们继续追踪loadBeanDefinitions(resources)的内部处理逻辑。

loadBeanDefinitions(resources)
// AbstractBeanDefinitionReader#loadBeanDefinitions
@Override
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
	Assert.notNull(resources, "Resource array must not be null");
	int count = 0;
	for (Resource resource : resources) {
		count += loadBeanDefinitions(resource);
	}
	return count;
}
// XmlBeanDefinitionReader#loadBeanDefinitions
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
	return loadBeanDefinitions(new EncodedResource(resource));
}


public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
	// 部分省略
	Set currentResources = this.resourcesCurrentlyBeingLoaded.get();
	if (!currentResources.add(encodedResource)) {
		throw new BeanDefinitionStoreException(
				"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
	}
	// 获取资源文件字节流
	try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
		InputSource inputSource = new InputSource(inputStream);
		if (encodedResource.getEncoding() != null) {
			inputSource.setEncoding(encodedResource.getEncoding());
		}
		// 从XML资源中加载BeanDefinitions
		return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
	}
	catch (IOException ex) {
		throw new BeanDefinitionStoreException(
				"IOException parsing XML document from " + encodedResource.getResource(), ex);
	}
	finally {
		currentResources.remove(encodedResource);
		if (currentResources.isEmpty()) {
			this.resourcesCurrentlyBeingLoaded.remove();
		}
	}
}

如上代码大致流程如下:

  1. 获取当前文件字节流,实例化InputSource。
    	// InputSource
        public InputSource (InputStream byteStream){
            setByteStream(byteStream);
        }
        public void setByteStream (InputStream byteStream){
            this.byteStream = byteStream;
        }
    
  2. 设置资源编码格式,真正开始执行XML解析动作。

做了这么多准备动作,终于开始进入实际的加载,我们继续。

doLoadBeanDefinitions(inputSource, resource())
// XmlBeanDefinitionReader#doLoadBeanDefinitions
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
		throws BeanDefinitionStoreException {

	try {
		// 转换为document对象
		document doc = doLoaddocument(inputSource, resource);
		// 获取注册成功的BeanDefinition
		int count = registerBeanDefinitions(doc, resource);
		// 部分省略
		return count;
	}
	// 部分省略
}

如何完成注册呢?

// XmlBeanDefinitionReader#registerBeanDefinitions
public int registerBeanDefinitions(document doc, Resource resource) throws BeanDefinitionStoreException {
	// 通过反射实例化并返回BeanDefinitiondocumentReader对象,
	// 该对象用于解析xml格式的bean定义
	BeanDefinitiondocumentReader documentReader = createBeanDefinitiondocumentReader();
	// 获取当前已经注册的BeanDefinition个数
	int countBefore = getRegistry().getBeanDefinitionCount();
	// 注册BeanDefinition
	documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
	// 返回当前注册成功的BeanDefinition个数
	return getRegistry().getBeanDefinitionCount() - countBefore;
}

以上流程大致如下:

  1. 通过反射实例化并返回用于解析xml格式的bean定义BeanDefinitiondocumentReader对象。
  2. 注册BeanDefinition。
  3. 返回当前注册成功的BeanDefinition个数。
registerBeanDefinitions(doc, createReaderContext(resource))

接下来我们来简单看看xml配置元数据的解析步骤。

// DefaultBeanDefinitiondocumentReader#registerBeanDefinitions
@Override
public void registerBeanDefinitions(document doc, XmlReaderContext readerContext) {
	this.readerContext = readerContext;
	doRegisterBeanDefinitions(doc.getdocumentElement());
}
 // DefaultBeanDefinitiondocumentReader#doRegisterBeanDefinitions
@SuppressWarnings("deprecation")  // for Environment.acceptsProfiles(String...)
protected void doRegisterBeanDefinitions(Element root) {
	// 任何的元素都会在此方法递归。
	// 若当前parent为空则创建子delegate,并引用父delegate
	BeanDefinitionParserDelegate parent = this.delegate;
	this.delegate = createDelegate(getReaderContext(), root, parent);
	// 确定给定的节点是否表明默认命名空间。
	// 也就是我们配置文件的的xmlns属性“http://www.springframework.org/schema/beans”
	if (this.delegate.isDefaultNamespace(root)) {
		// 获取当前的profile属性名
		String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
		// 判空
		if (StringUtils.hasText(profileSpec)) {
			// MULTI_VALUE_ATTRIBUTE_DELIMITERS=“,; ”
			// 按照","或";"或" "作为分隔符分割
			String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
					profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			// 获取spring.profiles.active属性值,判断specifiedProfiles是否包含,false则return
			if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
				// 部分省略
				return;
			}
		}
	}
	// 空方法,可以通过重写的方式前置处理
	preProcessXml(root);
	// 开始解析
	parseBeanDefinitions(root, this.delegate);
	// 空方法,通过重写后置处理
	postProcessXml(root);
	this.delegate = parent;
}

大致步骤如下:

  1. 创建BeanDefinitionParserDelegate,它是用于解析资源文件的委托类。

  2. isDefaultNamespace(root)检查被定义的命名空间是否是默认命名空间。

    // BeanDefinitionParserDelegate
    public boolean isDefaultNamespace(Node node) {
    	return isDefaultNamespace(getNamespaceURI(node));
    }
    // 这边获取到的就是的xmlns属性,xmlns:命名空间
    @Nullable
    public String getNamespaceURI(Node node) {
    	return node.getNamespaceURI();
    }
    
    // BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans"
    public boolean isDefaultNamespace(@Nullable String namespaceUri) {
    	return !StringUtils.hasLength(namespaceUri) || BEANS_NAMESPACE_URI.equals(namespaceUri);
    }
    
  3. 第二步若为true则获取的profile属性值,若该属性值不为空,进行检查当前节点是否满足环境配置。profile用于指定当前运行环境的启用配置。

    示例:

    public class XmlTest {
        static ApplicationContext context;
        static {
            context = new ClassPathXmlApplicationContext("classpath*:config
    @Nullable
    public AbstractBeanDefinition parseBeanDefinitionElement(
    		Element ele, String beanName, @Nullable BeanDefinition containingBean) {
    
    	this.parseState.push(new BeanEntry(beanName));
    
    	String className = null;
    	// 判断是否存在class属性
    	if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
    		className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
    	}
    	String parent = null;
    	// 判断是否存在parent属性。
    	if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
    		parent = ele.getAttribute(PARENT_ATTRIBUTE);
    	}
    
    	try {
    		// 创建AbstractBeanDefinition
    		AbstractBeanDefinition bd = createBeanDefinition(className, parent);
    		// 将上定义的属性set到bd对象
    		parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
    		bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DEscriptION_ELEMENT));
    		// 解析
    		parsemetaElements(ele, bd);
    		// 解析
    		parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
    		// 解析
    		parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
    		// 解析
    		parseConstructorArgElements(ele, bd);
    		// 解析
    		parsePropertyElements(ele, bd);
    		// 解析
    		parseQualifierElements(ele, bd);
    		// 设置对应配置文件Resource
    		bd.setResource(this.readerContext.getResource());
    		bd.setSource(extractSource(ele));
    		return bd;
    	}
    	// 部分省略
    	finally {
    		this.parseState.pop();
    	}
    	return null;
    }
    

    我们先回顾一下标签的属性及子标签:

    标签属性
    id设置在容器中的唯一标识
    namebean的名称定义
    class类全限定名
    scopesingleton:默认单例;prototype:多例
    init-method类初始化方法
    destory-method类销毁方法
    parent指代“父bean”,不指代父类。
    primary是否注入优先,默认:false
    abstract声明为抽象bean
    depends-on声明该bean与其它bean的依赖关系
    factory-bean指定bean工厂
    factory-method指定bean工厂方法
    autowire自动装配模式(1)no:默认值;(2)byName:根据bean名称自动装配;(3)byType:按照类型进行装配;(4)constructor:通过构造器自动装配;(5)default:使用的default-autowire属性配置。
    autowire-candidate默认为true,表示允许自动装配注入到其它bean
    lazy-init默认为false,表示在IOC容器启动的时候进行实例化;true,则代表使用的时候进行实例化。
    标签的子标签
    源数据设置
    bean成员变量属性设置
    构造方法参数设置
    描述信息
    方法注入
    指定注入bean名称
    方法替换

    大致流程如下:

    1. 创建AbstractBeanDefinition。
    2. 解析属性。
      // BeanDefinitionParserDelegate#parseBeanDefinitionAttributes
      public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
      		@Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {
      	// 判断是否存在single属性配置
      	if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
      		error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
      	}
      	// 是否存在scope属性
      	else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
      		bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
      	}
      	else if (containingBean != null) {
      		// Take default from containing bean in case of an inner bean definition.
      		bd.setScope(containingBean.getScope());
      	}
      	// 是否存在abstract属性
      	if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
      		bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
      	}
      	// 设置lazt-init属性,默认false
      	String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
      	if (isDefaultValue(lazyInit)) {
      		lazyInit = this.defaults.getLazyInit();
      	}
      	bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
      	
      	// 设置自动装配模式默认为0及默认自动装配
      	String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
      	bd.setAutowireMode(getAutowireMode(autowire));
      
      	// 是否存在depends-on属性
      	if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
      		String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
      		bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
      	}
      	
      	// 是否存在autowire-candidate属性,默认为true
      	String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
      	if (isDefaultValue(autowireCandidate)) {
      		String candidatePattern = this.defaults.getAutowireCandidates();
      		if (candidatePattern != null) {
      			String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
      			bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
      		}
      	}
      	else {
      		bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
      	}
      	
      	// 是否存在primary属性
      	if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
      		bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
      	}
      	
      	// 是否存在init-method属性
      	if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
      		String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
      		bd.setInitMethodName(initMethodName);
      	}
      	else if (this.defaults.getInitMethod() != null) {
      		bd.setInitMethodName(this.defaults.getInitMethod());
      		bd.setEnforceInitMethod(false);
      	}
      
      	// 是否存在destroy-method属性
      	if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
      		String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
      		bd.setDestroyMethodName(destroyMethodName);
      	}
      	else if (this.defaults.getDestroyMethod() != null) {
      		bd.setDestroyMethodName(this.defaults.getDestroyMethod());
      		bd.setEnforceDestroyMethod(false);
      	}
      	
      	// 是否存在factory-method属性
      	if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
      		bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
      	}
      	
      	// 是否存在factory-bean属性
      	if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
      		bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
      	}
      	return bd;
      }
      
    3. 解析子标签(源码就不在这里贴了,可以自行查看)。
    4. 返回解析并组装完毕后的AbstractBeanDefinition。

    BeanDefinition已经获取到了,接下来就进行到注册这一步了,接下来我们来查看它的处理逻辑。

    registerBeanDefinition(bdHolder, getReaderContext().getRegistry())
    // BeanDefinitionParserDelegate#registerBeanDefinition
    public static void registerBeanDefinition(
    		BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
    		throws BeanDefinitionStoreException {
    	// 使用beanName注册BeanDefinition
    	String beanName = definitionHolder.getBeanName();
    	registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    
    	// 别名注册
    	String[] aliases = definitionHolder.getAliases();
    	if (aliases != null) {
    		for (String alias : aliases) {
    			registry.registerAlias(beanName, alias);
    		}
    	}
    }
    

    跟进查看注册逻辑:

    // DefaultListableBeanFactory#registerBeanDefinition
    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
    		throws BeanDefinitionStoreException {
    
    	Assert.hasText(beanName, "Bean name must not be empty");
    	Assert.notNull(beanDefinition, "BeanDefinition must not be null");
    
    	if (beanDefinition instanceof AbstractBeanDefinition) {
    		try {
    			// beanDefinition校验
    			((AbstractBeanDefinition) beanDefinition).validate();
    		}
    		// 部分省略
    	}
    	// 按beanName从beanDefinitionMap获取beanDefinition
    	BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    	if (existingDefinition != null) {
    		// 若根据beanName可以获取到beanDefinition,
    		// 则判断该beanDefinition是否允许覆盖
    		if (!isAllowBeanDefinitionOverriding()) {
    			throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
    		}
    		// 部分省略
    		// 允许覆盖的前提下,将当前beanDefinition放到beanDefinitionMap中
    		this.beanDefinitionMap.put(beanName, beanDefinition);
    	}
    	else {
    		// 检查是否存在被标记为已创建状态的bean
    		if (hasBeanCreationStarted()) {
    			// Cannot modify startup-time collection elements anymore (for stable iteration)
    			synchronized (this.beanDefinitionMap) {
    				this.beanDefinitionMap.put(beanName, beanDefinition);
    				List updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
    				updatedDefinitions.addAll(this.beanDefinitionNames);
    				updatedDefinitions.add(beanName);
    				this.beanDefinitionNames = updatedDefinitions;
    				removeManualSingletonName(beanName);
    			}
    		}
    		else {
    			// 进入启动注册阶段
    			// key:beanName,value:BeanDefinition,将当前beanDefinition放到beanDefinitionMap中
    			this.beanDefinitionMap.put(beanName, beanDefinition);
    			// 将BeanDefinition的名称add到beanDefinitionNames中(for)
    			this.beanDefinitionNames.add(beanName);
    			// 处理environment、systemProperties、systemEnvironment、applicationStartup等bean
    			removeManualSingletonName(beanName);
    		}
    		this.frozenBeanDefinitionNames = null;
    	}
    
    	if (existingDefinition != null || containsSingleton(beanName)) {
    		// 重置当前beanName的所有bean定义
    		resetBeanDefinition(beanName);
    	}
    	else if (isConfigurationFrozen()) {
    		clearByTypeCache();
    	}
    }
    

    至此我们也终于大致阅读完obtainFreshBeanFactory()的源码,其它具体细节有兴趣可以自行阅读。

    总结

    至此,我们已经了解了refresh()核心方法的前两个prepareRefresh()和obtainFreshBeanFactory()方法,从初始化并校验环境配置,初始化应用监听与事件,到解析资源配置文件,将文件中关于bean定义加载到beanFactory并返回beanFactory的过程。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/351196.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号