源码阅读传送门
上一章我们了解了IOC容器的相关概念、如何通过代码实例化容器以及容器初始化的核心方法refresh()
,本章开始初探refresh()
,在阅读源码前,我们有必要先了解什么是BeanFactory
以及BeanDefinition
,这将有利于我们对接来下源码的理解。
BeanFactory顾名思义,Bean的工厂,用于创建与管理Bean。
从上图我们可以看到ApplicationContext
继承了两个BeanFactory
的子接口:
ListableBeanFactory
:listable(可列举的),BeanFactory
只能获取单个Bean,ListableBeanFactory
可以获取多个Bean。HierarchicalBeanFactory
:hierarchical(分层),可以通过配置的方式设置父类的bean工厂。Spring IOC容器管理一个或多个Bean,这些bean使用提供给容器的配置元数据创建的(例如通过xml定义的形式)。在容器本身,这些Bean表示为
BeanDefinition
对象。
BeanDefinition
主要包含哪些信息呢?
源码如下:
/**
* BeanDefinition用于描述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
/**
* 设置该bean的父名称
*/
void setParentName(@Nullable String parentName);
/**
* 获取···
*/
@Nullable
String getParentName();
/**
* 为该bean指定bean类名
*/
void setBeanClassName(@Nullable String beanClassName);
/**
* 获取···
*/
@Nullable
String getBeanClassName();
/**
* 设置作用域
* @see #SCOPE_SINGLETON
* @see #SCOPE_PROTOTYPE
*/
void setScope(@Nullable String scope);
/**
* 获取作用域
*/
@Nullable
String getScope();
/**
* 设置是否懒加载
*/
void setLazyInit(boolean lazyInit);
/**
* 判断是否懒加载
*/
boolean isLazyInit();
/**
* 设置此bean初始化所依赖的bean名称,
* bean工厂将保证首先初始化这些bean
*/
void setDependsOn(@Nullable String... dependsOn);
/**
* 获取依赖的bean名称数组
*/
@Nullable
String[] getDependsOn();
/**
* 设置该bean是否可以自动注入
*/
void setAutowireCandidate(boolean autowireCandidate);
/**
* 返回···
*/
boolean isAutowireCandidate();
/**
* 设置该bean是否为主要候选bean
*/
void setPrimary(boolean primary);
/**
* 返回···
*/
boolean isPrimary();
/**
* 设置FactoryBean名称
*/
void setFactoryBeanName(@Nullable String factoryBeanName);
/**
* 返回···
*/
@Nullable
String getFactoryBeanName();
/**
* 设置工厂方法名称,
* 如果有工厂方法,此方法将使用构造函数参数调用,如果没有指定参数则不使用。
*/
void setFactoryMethodName(@Nullable String factoryMethodName);
/**
* 返回···
*/
@Nullable
String getFactoryMethodName();
/**
* 设置该bean指定构造函数参数值。
*/
ConstructorArgumentValues getConstructorArgumentValues();
/**
* 返回···
*/
default boolean hasConstructorArgumentValues() {
return !getConstructorArgumentValues().isEmpty();
}
/**
* 获取要应用于bean实例的属性值。
*/
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();
/**
* 设置bean描述
*/
void setDescription(@Nullable String description);
/**
* 返回bean描述
*/
@Nullable
String getDescription();
// Read-only attributes
/**
* 返回此bean定义的可解析类型。
*/
ResolvableType getResolvableType();
/**
* 是否单例
*/
boolean isSingleton();
/**
* 是否原型
*/
boolean isPrototype();
/**
* 是否抽象
*/
boolean isAbstract();
/**
* 返回此bean定义来自的资源的描述
*/
@Nullable
String getResourceDescription();
/**
* 返回原始bean定义,如果没有则为空。
*/
@Nullable
BeanDefinition getOriginatingBeanDefinition();
}
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()大致流程如下:
MissingRequiredPropertiesException: The following properties were declared as required but could not be resolved: [缺失的配置参数数组]
)
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()
源码,我们可以了解到大致流程:
判断BeanFactory是否已经创建,若已经创建则销毁所有已创建的bean、并把beanFactory置空。
// AbstractRefreshableApplicationContext#hasBeanFactory()
protected final boolean hasBeanFactory() {
return (this.beanFactory != null);
}
创建DefaultListableBeanFactory
(该类为BeanFactory
的一个默认实现),并将其设置为容器的parentBeanFactory
。
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);
}
}
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)
大致步骤:
XmlBeanDefinitionReader
(读取通过Xml文件中配置Bean定义的工具类)、属性配置。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)
大致步骤如下:
getConfigResources()
方法的前提下,通过重写方法指定逻辑获取配置文件数组(默认返回null),从指定配置文件中加载Bean。// AbstractXmlApplicationContext#getConfigResources
@Nullable
protected Resource[] getConfigResources() {
return null;
}
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
/**
* 读取配置转换为BeanDefinition并注册到beanFactory
* @param location 本地资源文件路径
* @param actualResources 解析过程中的实际资源集合
*/
public int loadBeanDefinitions(String location, @Nullable Set<Resource> 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)
大致流程如下:
getResourceLoader()
获得资源加载器。
@Override
@Nullable
public ResourceLoader getResourceLoader() {
// this.resourceLoader即AbstractXmlApplicationContext。
// 前面源码中有讲解,
// 没有印象的可以再去回顾AbstractXmlApplicationContext#loadBeanDefinitions
return this.resourceLoader;
}
通过资源解析器根据资源文件路径解析并加载(该节点以下的源码,感兴趣可以看看,不感兴趣可以直接跳过)。
// 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/*Config.xml”,则会寻找所有classpath路径config文件夹下所有以“Config.xml”为后缀的文件
if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
// 根据路径查找匹配资源文件
return findPathMatchingResources(locationPattern);
}
else {
// 若未包含以上字符,则寻找并加载所有classpath路径下的指定名称的配置文件。
return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
}
}
else {
int prefixEnd = (locationPattern.startsWith("war:") ? locationPattern.indexOf("*/") + 1 :
locationPattern.indexOf(':') + 1);
// 判断是否包含特殊字符
if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
return findPathMatchingResources(locationPattern);
}
else {
// 单文件根据名称加载
// 我们的demo中直接走这个分支
return new Resource[] {getResourceLoader().getResource(locationPattern)};
}
}
}
具体查找文件的方法就不继续延伸了,有兴趣的可以展开阅读。
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));
}
/**
* 从指定文件中加载BeanDefinition并返回个数
*/
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
// 部分省略
Set<EncodedResource> 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();
}
}
}
如上代码大致流程如下:
InputSource
。 // InputSource
public InputSource (InputStream byteStream){
setByteStream(byteStream);
}
public void setByteStream (InputStream byteStream){
this.byteStream = byteStream;
}
做了这么多准备动作,终于开始进入实际的加载,我们继续。
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;
}
以上流程大致如下:
BeanDefinitionDocumentReader
对象。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;
}
大致步骤如下:
创建BeanDefinitionParserDelegate
,它是用于解析资源文件的委托类。
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);
}
第二步若为true
则获取
的profile
属性值,若该属性值不为空,进行检查当前节点是否满足环境配置。profile
用于指定当前运行环境的启用配置。
示例:
public class XmlTest {
static ApplicationContext context;
static {
context = new ClassPathXmlApplicationContext("classpath*:config/*Config.xml");
}
@Test
public void instanceBeanBaseOnConstructorByXml() {
Car car = (Car) context.getBean("constructorCar");
System.out.println(car.toString());
}
@Test
public void secInstanceBeanBaseOnConstructorByXml() {
Car car = (Car) context.getBean("secConstructorCar");
System.out.println(car.toString());
}
}
修改demo中的xml文件配置
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<beans profile="dev test">
<bean id="constructorCar" class="com.zt.bean.Car">
<constructor-arg name="brand" value="Benz"/>
<constructor-arg name="price" value="200"/>
<constructor-arg name="color" value="white"/>
bean>
beans>
<beans profile="dev">
<bean id="secConstructorCar" class="com.zt.bean.Car">
<constructor-arg name="brand" value="Benz"/>
<constructor-arg name="price" value="200"/>
<constructor-arg name="color" value="white"/>
bean>
beans>
beans>
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'secConstructorCar' available
···
Car(brand=Benz, price=200.0, color=white)
parseBeanDefinitions(root, this.delegate)
开始配置解析。
parseBeanDefinitions(root, this.delegate)
// DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
// 判断是否是Spring默认命名空间,
// true,例如
// false,例如等
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
// 判断当前节点是否为一个有效元素,比如:注释
if (node instanceof Element) {
Element ele = (Element) node;
// 判断方式如上
if (delegate.isDefaultNamespace(ele)) {
// 默认命名空间元素解析
parseDefaultElement(ele, delegate);
}
else {
// 非默认命名空间元素解析
delegate.parseCustomElement(ele);
}
}
}
}
else {
// 非默认命名空间元素解析
delegate.parseCustomElement(root);
}
}
我们先查看默认命名空间元素是如何解析的:
// DefaultBeanDefinitionDocumentReader#parseDefaultElement
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
// 判断当前节点名称是否为‘import’
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
// 判断当前节点名称是否为‘alias’
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
// 判断当前节点名称是否为‘bean’
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
// 判断当前节点名称是否为‘beans’
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// 递归 下的所有节点
doRegisterBeanDefinitions(ele);
}
}
本文暂时只看processBeanDefinition(ele, delegate)
分支。
processBeanDefinition(ele, delegate)
// DefaultBeanDefinitionDocumentReader#processBeanDefinition
// 处理给定的bean元素,解析bean的定义并注册。
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 解析当前 转换为BeanDefinitionHolder
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
// 自定义属性及子标签解析
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// BeanDefinition注册
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// 触发注册事件
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
大致处理流程如下:
delegate.parseBeanDefinitionElement(ele)
将
定义解析为BeanDefinitionHolder
。BeanDefinitionHolder
持有着BeanDefinition、beanName及aliases(别名)。public class BeanDefinitionHolder implements BeanMetadataElement {
private final BeanDefinition beanDefinition;
private final String beanName;
@Nullable
private final String[] aliases;
// 省略
}
自定义属性及子标签解析。我们先从第一步,查看如何解析为BeanDefinitionHolder
。
parseBeanDefinitionElement(ele)
// BeanDefinitionParserDelegate#parseBeanDefinitionElement
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
// 获取 的id
String id = ele.getAttribute(ID_ATTRIBUTE);
// 获取 的name
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List<String> aliases = new ArrayList<>();
// 获取是否有name属性的定义
if (StringUtils.hasLength(nameAttr)) {
// 将名称按照","或";"或" "作为分隔符分割
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
// 若 未定义ID属性,并且name属性不为空,
// 则beanName=aliases.remove(0)
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
// 部分省略
}
if (containingBean == null) {
// 名称唯一性检查
checkNameUniqueness(beanName, aliases, ele);
}
// 创建BeanDefinition实例
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
// 若 标签未指定id与name,则为true
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
// 生成beanName
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
// 生成beanName为类全限定名+容器中已存在的名称个数+1(从0开始)
// 例如
// beanName = com.zt.bean.Car#0
beanName = this.readerContext.generateBeanName(beanDefinition);
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
// 部分省略
} catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
代码步骤大致如下:
的id、name以及aliases等信息,判断IOC容器中是否存在同名beanName。parseBeanDefinitionElement(ele, beanName, containingBean)
创建BeanDefinition实例。
定义。BeanDefinitionHolder
,通过构造方法设置beanDefinition、beanName、aliases。第二步是怎么创建BeanDefinition实例的呢?
// BeanDefinitionParserDelegate#parseBeanDefinitionElement
/**
* 解析bean定义,过程中出现异常则返回null
*/
@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 | 设置在容器中的唯一标识 |
name | bean的名称定义 |
class | 类全限定名 |
scope | singleton:默认单例;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:使用 |
autowire-candidate | 默认为true,表示允许自动装配注入到其它bean |
lazy-init | 默认为false,表示在IOC容器启动的时候进行实例化;true,则代表使用的时候进行实例化。 |
源数据设置 | |
bean成员变量属性设置 | |
构造方法参数设置 | |
描述信息 | |
方法注入 | |
指定注入bean名称 | |
方法替换 |
大致流程如下:
AbstractBeanDefinition
。
属性。/**
* 解析标签属性配置赋予到bd
*/
// 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;
}
子标签(源码就不在这里贴了,可以自行查看)。AbstractBeanDefinition
。BeanDefinition
已经获取到了,接下来就进行到注册这一步了,接下来我们来查看它的处理逻辑。
registerBeanDefinition(bdHolder, getReaderContext().getRegistry())
/**
* 注册到容器
*/
// BeanDefinitionReaderUtils#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<String> 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的过程。