Spring——IOC源码解析上

demo

读取配置文件启动Spring:

1
2
3
4
5
6
7
public class IOCDemo {
public static void main (String args[]){
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application-ioc.xml");
IOCService iocService=context.getBean(IOCService.class);
System.out.println(iocService.hollo());
}
}

ClassPathXmlApplicationContext

继承关系

继承关系图:

Spring——IOC源碼解析_2020-04-13-16-16-22.png

最上方的 ApplicationContext 则是大名鼎鼎的Spring核心上下文了。

左下角的就是ClassPathXmlApplicationContext、与它同级的是FileSystemXmlApplicationContext。都是通过加载配置文件来启动Spring的,只不过一个是从程序内加载一个是从系统内加载。

AnnotationConfigApplicationContext比较值得我们关注,这个类是用来处理注解式编程的。详细请移步

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
//配置文件数组
private Resource[] configResources;

// 指定ApplicationContext的父容器
public ClassPathXmlApplicationContext(ApplicationContext parent) {
super(parent);
}

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {

super(parent);
// 根据提供的路径,处理成配置文件数组(以分号、逗号、空格、tab、换行符分割)
setConfigLocations(configLocations);

if (refresh) {
refresh();
}
}
}

类构造主要有 setConfigLocationsrefresh 这两个方法,这两个方法也是IOC的核心。

setConfigLocations 方法主要工作:

  1. 创建环境对象ConfigurableEnvironment
  2. 处理ClassPathXmlApplicationContext传入的字符串中的占位符

refresh 方法主要工作:

  1. 检查环境
  2. 创建BeanFactory
  3. 解析xml配置文件
  4. 创建Bean
  5. 注册Bean
  6. 扩展点
  7. 初始化

setConfigLocations()

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public void setConfigLocations(String... locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
//往下看
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}


protected String resolvePath(String path) {
return getEnironment().resolveRequiredPlaceholders(path);
}

这里会读取传入的 locations 数组并遍历,具体操作是由resolvePath 方法实现。

创建环境变量

看一下 getEniroment 方法:

1
2
3
4
5
6
public ConfigurableEnvironment getEnvironment() {
if (this.environment == null) {
this.environment = createEnvironment();
}
return this.environment;
}

ConfigurableEnvironment

继承关系图:

Spring——IOC源碼解析_2020-04-15-14-38-24.png

它直接继承类 EnvironmentConfigurablePropertyResolver

这个接口比较重要的两部分作用:

  • spring.profile配置
  • 系统资源Property

接着看 createEnvironment() 方法:

1
2
3
protected ConfigurableEnvironment createEnvironment() {
return new StandardEnvironment();
}

返回 StandardEnvironment 类,而这个类中的customizePropertySources 方法就会往资源列表中添加Java进程中的变量和系统的环境变量:

1
2
3
4
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}

处理占位符

回到 resovePath.resolveRequiredPlaceholders 方法:

这个方法主要就是处理所有使用${}方式的占位符,这里主要是为了处理 ClassPathXmlApplicationContext 传过来的占位符。

1
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:${prefixName}-spring.xml");

refresh

读取环境及系统变量、配置文件名称解析完毕后,就到了最关键的一步refresh 方法。

它也是spring管理bean的核心,bean的创建、注册、初始化都由这个方法完成

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//做一些准备工作,记录容器的启动时间、标记“已启动”状态、检查环境变量等.
prepareRefresh();

// BeanFactory的初始化、Bean的加载和注册等事件.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);

try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);

// Initialize message source for this context.
initMessageSource();

// Initialize event multicaster for this context.
initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.
onRefresh();

// Check for listener beans and register them.
registerListeners();

// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.
finishRefresh();
}

catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}

// Destroy already created singletons to avoid dangling resources.
destroyBeans();

// Reset 'active' flag.
cancelRefresh(ex);

// Propagate exception to caller.
throw ex;
}

finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}

检查环境

prepareRefresh 方法主要做一些准备工作,记录容器的启动时间、标记“已启动”状态、检查环境变量等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);

if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}

// 初始化加载配置文件方法,并没有具体实现,一个留给用户的扩展点
initPropertySources();

// 检查环境变量
getEnvironment().validateRequiredProperties();

this.earlyApplicationEvents = new LinkedHashSet<>();
}

这个方法最重要的是倒数二三行,具体详情请访问:准备环境

obtainFreshBeanFactory()*

这个方法很长,这里先总结它的主要工作:

  • 初始化一个ConfigurableListableBeanFactory容器
  • Rousource接口处理xml配置文件的流,解析配置文件
  • 根据解析出的配置dom,创建BeanDefinition示例
  • 注册了所有的BeanDefinition到beanDefinitionMap

源码:

1
2
3
4
5
6
7
8
9
10
11
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 核心
refreshBeanFactory();

// 返回刚刚创建的 BeanFactory
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}

解析这个方法之前,我们先要了解两个核心类 DefaultListableBeanFactoryBeanDefinition

DefaultListableBeanFactory

继承关系:

Spring——IOC源碼解析_2020-04-15-15-37-36.png

BeanFacoty 有三个直接子类 ListableBeanFactoryHierarchicalBeanFactoryAutowireCapableBeanFactory;

DefaultListableBeanFactory 为最终默认实现,它实现了所有接口。

实际上我们应用spring也是通过ApplicationContex和DefaultListableBeanFactory一起来完成的

BeanDefinition

我们知道 BeanFactory 是一个 Bean 容器,而 BeanDefinition 就是 Bean 的一种形式(它里面包含了 Bean 指向的类、是否单例、是否懒加载、Bean 的依赖关系等相关的属性)。BeanFactory 中就是保存的 BeanDefinition。

看看BeanDefinition的接口源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

// Bean的生命周期,默认只提供sington和prototype两种,在WebApplicationContext中还会有request, session, globalSession, application, websocket 等
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;


// 设置父Bean
void setParentName(String parentName);

// 获取父Bean
String getParentName();

// 设置Bean的类名称
void setBeanClassName(String beanClassName);

// 获取Bean的类名称
String getBeanClassName();


// 设置bean的scope
void setScope(String scope);

String getScope();

// 设置是否懒加载
void setLazyInit(boolean lazyInit);

boolean isLazyInit();

// 设置该Bean依赖的所有Bean
void setDependsOn(String... dependsOn);

// 返回该Bean的所有依赖
String[] getDependsOn();

// 设置该Bean是否可以注入到其他Bean中
void setAutowireCandidate(boolean autowireCandidate);

// 该Bean是否可以注入到其他Bean中
boolean isAutowireCandidate();

// 同一接口的多个实现,如果不指定名字的话,Spring会优先选择设置primary为true的bean
void setPrimary(boolean primary);

// 是否是primary的
boolean isPrimary();

// 指定工厂名称
void setFactoryBeanName(String factoryBeanName);
// 获取工厂名称
String getFactoryBeanName();
// 指定工厂类中的工厂方法名称
void setFactoryMethodName(String factoryMethodName);
// 获取工厂类中的工厂方法名称
String getFactoryMethodName();

// 构造器参数
ConstructorArgumentValues getConstructorArgumentValues();

// Bean 中的属性值,后面给 bean 注入属性值的时候会说到
MutablePropertyValues getPropertyValues();

// 是否 singleton
boolean isSingleton();

// 是否 prototype
boolean isPrototype();

// 如果这个 Bean 是被设置为 abstract,那么不能实例化,常用于作为 父bean 用于继承
boolean isAbstract();

int getRole();
String getDescription();
String getResourceDescription();
BeanDefinition getOriginatingBeanDefinition();
}

refreshBeanFactory()

我们回到 obtainFreshBeanFactory,看一下 refreshBeanFactory 方法。

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
protected final void refreshBeanFactory() throws BeansException {
// 判断当前ApplicationContext是否存在BeanFactory,如果存在的话就销毁所有 Bean,关闭 BeanFactory
// 注意,一个应用可以存在多个BeanFactory,这里判断的是当前ApplicationContext是否存在BeanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 初始化DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());

// 设置 BeanFactory 的两个配置属性:是否允许 Bean 覆盖、是否允许循环引用
customizeBeanFactory(beanFactory);

// 加载 Bean 到 BeanFactory 中
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}

进入 loadBeanDefinitions方法。

loadBeanDefinitions()
读取配置文件
1
2
3
4
5
6
7
8
9
10
11
12
@Overrideprotected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 实例化XmlBeanDefinitionReader
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

// 初始化 BeanDefinitionReader
initBeanDefinitionReader(beanDefinitionReader);
// 接着往下看
loadBeanDefinitions(beanDefinitionReader);
}
1
2
3
4
5
6
7
8
9
10
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}

第一个if是看有没有系统指定的配置文件,如果没有的话就走第二个if加载我们最开始传入的 classpath:application-ioc.xml

XmlBeanDefinitionReader 是我们解析xml配置的核心类。

XmlBeanDefinitionReader

,它的父类是 AbstractBeanDefinitionReader 它实现了 BeanDefinitionReader 接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
if (this.registry instanceof ResourceLoader) {
this.resourceLoader = (ResourceLoader)this.registry;
} else {
this.resourceLoader = new PathMatchingResourcePatternResolver();
}

if (this.registry instanceof EnvironmentCapable) {
this.environment = ((EnvironmentCapable)this.registry).getEnvironment();
} else {
this.environment = new StandardEnvironment();
}

}

它提供了读取环境变量,加载location资源,以及 BeanDefinitionRegistry的 注册Bean方法。

Resourse
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}

Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
//获取文件流
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//加载
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}

中间省略了一些源码,其实这几个方法的目的就是把流交给 Resource 接口来处理,它的每一个实现类都代表了一种资源的访问策略,这里用的就是EncodedResource。

DOM解析

进去看 doLoadBeanDefinitions() 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//将 xml 文件转换为 Document 对象
Document doc = doLoadDocument(inputSource, resource);
//根据Document对象注册Bean
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}

xml转dom解析这里不用费神了,主要是 registerBeanDefinitions()

注册 Bean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//构建读取Document的工具类
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//获取已注册的bean数量
int countBefore = getRegistry().getBeanDefinitionCount();
// 在这接着往下看
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//总注册的bean减去之前注册的bean就是本次注册的bean
return getRegistry().getBeanDefinitionCount() - countBefore;
}

@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
//获取Document的根节点
Element root = doc.getDocumentElement();
//继续往下
doRegisterBeanDefinitions(root);
}

protected void doRegisterBeanDefinitions(Element root) {
// 当前根节点
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);

if (this.delegate.isDefaultNamespace(root)) {
// 获取 <beans ... profile="***" /> 中的 profile参数与当前环境是否匹配,如果不匹配则不再进行解析
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isInfoEnabled()) {
logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
// 前置扩展点
preProcessXml(root);
// 往下看
parseBeanDefinitions(root, this.delegate);
// 后置扩展点
postProcessXml(root);

this.delegate = parent;
}

接下来就是具体解析xml配置文件的方法 parseBeanDefinitions();

解析xml标签
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
// default namespace 涉及到的就四个标签 <import />、<alias />、<bean /> 和 <beans />
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)) {
// 解析 default namespace 下面的几个元素
parseDefaultElement(ele, delegate);
}
else {
// 解析其他 namespace 的元素
delegate.parseCustomElement(ele);
}
}
}
}
else {
// 解析其他 namespace 的元素
delegate.parseCustomElement(root);
}
}

看一下 default 标签的处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
// 处理 <import /> 标签
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
// 处理 <alias /> 标签
// <alias name="fromName" alias="toName"/>
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
// 处理 <bean /> 标签定义
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// 处理 <beans /> 标签
doRegisterBeanDefinitions(ele);
}
}

看一下bean标签的处理方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
      //创建BeanDefinition
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}

看一下第一行的 parseBeanDefinitionElement 方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

List<String> aliases = new ArrayList<String>();

// 将 name 属性的定义按照 “逗号、分号、空格” 切分,形成一个 别名列表数组,
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}

String beanName = id;
// 如果没有指定id, 那么用别名列表的第一个名字作为beanName
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isDebugEnabled()) {
logger.debug("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}

if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}

// 根据 <bean ...>...</bean> 中的配置创建 BeanDefinition,然后把配置中的信息都设置到实例中,
// 这行执行完毕,一个 BeanDefinition 实例就出来了。等下接着往下看
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);

// <bean /> 标签完成
if (beanDefinition != null) {
// 如果没有设置 id 和 name,那么此时的 beanName 就会为 null
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);

String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
// 把 beanClassName 设置为 Bean 的别名
aliases.add(beanClassName);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Neither XML 'id' nor 'name' specified - " +
"using generated bean name [" + beanName + "]");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
// 返回 BeanDefinitionHolder
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}

return null;
}

看一下这个方法的 parseBeanDefinitionElement(Element ele, BeanDefinition containingBean)

这个方法就是根据配置创建 BeanDefinition 实例的方法,前面山路十八弯,其中解析xml占据了大部分源码。。。

创建 BeanDefinition*
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean) {

this.parseState.push(new BeanEntry(beanName));

String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}

try {
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
// 创建 BeanDefinition,然后设置类信息
AbstractBeanDefinition bd = createBeanDefinition(className, parent);

// 设置 BeanDefinition 的一堆属性,这些属性定义在 AbstractBeanDefinition 中
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

/**
* 下面的一堆是解析 <bean>......</bean> 内部的子元素,
* 解析出来以后的信息都放到 bd 的属性中
*/

// 解析 <meta />
parseMetaElements(ele, bd);
// 解析 <lookup-method />
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
// 解析 <replaced-method />
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
// 解析 <constructor-arg />
parseConstructorArgElements(ele, bd);
// 解析 <property />
parsePropertyElements(ele, bd);
// 解析 <qualifier />
parseQualifierElements(ele, bd);

bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));

return bd;
}
catch (ClassNotFoundException ex) {
error("Bean class [" + className + "] not found", ele, ex);
}
catch (NoClassDefFoundError err) {
error("Class that bean class [" + className + "] depends on not found", ele, err);
}
catch (Throwable ex) {
error("Unexpected failure during bean definition parsing", ele, ex);
}
finally {
this.parseState.pop();
}

return null;
}

通过 BeanDefinitionParserDelegate 类的 parseBeanDefinitionElement 进行元素解析,返回BeanDefinitionHolder,返回的实例包含了配置文件中配置的各种属性了,比如class、name、id、alias之类的属性。

注册Bean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 上面说的一堆
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
// 如果有自定义属性的话,进行相应的解析
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 注册Bean
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));
}
}

注册操作委托给了BeanDefinitionReaderUtils,看看真正注册Bean的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {

String beanName = definitionHolder.getBeanName();
// 注册这个 Bean
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

// 如果配置有别名的话,也要根据别名全部注册一遍
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}

这里我们要注意这个类 BeanDefinitionRegistry 接口, 我们注册Bean、删除Bean,用到的都是这个类。当然我们用的是它的实现类DefaultListableBeanFactory 的方法。

还要往里看。。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
@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 {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(...);
}
}

BeanDefinition oldBeanDefinition;

// 所有的 Bean 注册后都会被放入到这个beanDefinitionMap 中,查看是否已存在这个bean
oldBeanDefinition = this.beanDefinitionMap.get(beanName);

// 处理重复名称的 Bean 定义的情况
if (oldBeanDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
// 如果不允许覆盖的话,抛异常
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// 用框架定义的 Bean 覆盖用户自定义的 Bean
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(oldBeanDefinition)) {
// 用新的 Bean 覆盖旧的 Bean
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
else {
// log...用同等的 Bean 覆盖旧的 Bean
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
// 覆盖
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
// 判断是否已经有其他的 Bean 开始初始化了.注意,"注册Bean" 这个动作结束,Bean 依然还没有初始化 在 Spring 容器启动的最后,会 预初始化 所有的 singleton beans
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<String>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {


// 将 BeanDefinition 放到这个 map 中,这个 map 保存了所有的 BeanDefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
// 这是个 ArrayList,所以会按照 bean 配置的顺序保存每一个注册的 Bean 的名字
this.beanDefinitionNames.add(beanName);
// 这是个 LinkedHashSet,代表的是手动注册的 singleton bean,
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}

if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}

到这里已经初始化了 Bean 容器,的配置也相应的转换为了一个个BeanDefinition,然后注册了所有的 BeanDefinition 到beanDefinitionMap,

总结

其实这一长串源码下来,关于读取配置文件、创建Bean、加载Bean,实际上是:
BeanDefinitionReader 如何将 Resource 转换为 IoC 容器独特的数据存储对象:BeanDefinition

当然这里 bean 还没有初始化,只是完成了bean的注册。关于Bean初始化的内容请看下文 Spring——IOC源码解析下

文章目录
  1. 1. demo
  2. 2. ClassPathXmlApplicationContext
    1. 2.1. 继承关系
    2. 2.2. setConfigLocations()
      1. 2.2.1. 创建环境变量
        1. 2.2.1.1. ConfigurableEnvironment
      2. 2.2.2. 处理占位符
    3. 2.3. refresh
      1. 2.3.1. 检查环境
      2. 2.3.2. obtainFreshBeanFactory()*
        1. 2.3.2.1. DefaultListableBeanFactory
        2. 2.3.2.2. BeanDefinition
        3. 2.3.2.3. refreshBeanFactory()
          1. 2.3.2.3.1. loadBeanDefinitions()
            1. 2.3.2.3.1.1. 读取配置文件
            2. 2.3.2.3.1.2. XmlBeanDefinitionReader
            3. 2.3.2.3.1.3. Resourse
            4. 2.3.2.3.1.4. DOM解析
            5. 2.3.2.3.1.5. 注册 Bean
            6. 2.3.2.3.1.6. 解析xml标签
            7. 2.3.2.3.1.7. 创建 BeanDefinition*
            8. 2.3.2.3.1.8. 注册Bean
      3. 2.3.3. 总结
|