这个是接着上一篇来写,主要是这章内容比较多,还是分开来写吧!
一、AbstractBeanDefinition属性介绍
XML中的所有的属性都可以在GenericBeanDefinition中找到对应,GenericBeanDefinition只是子类实现,大部分通用的配置都在
其父类AbstractBeanDefinition中定义,来看一下AbstractBeanDefinition中有哪些属性定义,因为我看的是spring5.0版本,和作者的版本应该不一样,这里是少了两个属性的就是scope和singleton,我下面是spring5.0的源码:
1 /**
2 * bean的作用范围,对应bean的属性scope
3 */
4 @Nullable
5 private String scope = SCOPE_DEFAULT;
6
7 /**
8 * 是否是抽象,对应bean属性abstract
9 */
10 private boolean abstractFlag = false;
11
12 /**
13 * 是否延迟加载,对应bean属性lazy-init
14 */
15 private boolean lazyInit = false;
16
17 /**
18 * 自动注入模式,对应bean属性autowire
19 */
20 private int autowireMode = AUTOWIRE_NO;
21
22 /**
23 * 依赖检查,spring3.0之后弃用这个属性
24 */
25 private int dependencyCheck = DEPENDENCY_CHECK_NONE;
26
27 /**
28 * 用来表示一个bean的实例化依靠另一个bean先实例化,对应bean的属性depend-on
29 */
30 @Nullable
31 private String[] dependsOn;
32
33 /**
34 * autowireCandidate属性设置成flase时,这样容器在查找自动装配对象时,将不考虑该bean,<br>
35 * 即它不会被考虑作为其他bean的自动装配的候选者,但是该bean本身还是可以使用自动装配来注入其他bean的
36 */
37 private boolean autowireCandidate = true;
38
39 /**
40 * 自动装配时当出现多个bean候选者的时候,将作为首先,对应bean属性primary
41 */
42 private boolean primary = false;
43
44 /**
45 * 用于记录Qualifier,对应子元素qualifier
46 */
47 private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>();
48
49 /**
50 * 这个好像是新加的属性 TODO
51 */
52 @Nullable
53 private Supplier<?> instanceSupplier;
54
55 /**
56 * 允许访问非公开的构造器和方法,程序设置
57 */
58 private boolean nonPublicAccessAllowed = true;
59
60 /**
61 * 是否以一种宽松的方式解析构造函数,默认为true <br>
62 */
63 private boolean lenientConstructorResolution = true;
64
65 /**
66 * 对应bean属性factory-bean
67 */
68 @Nullable
69 private String factoryBeanName;
70
71 /**
72 * 对应bean属性,factory-method
73 */
74 @Nullable
75 private String factoryMethodName;
76
77 /**
78 * 记录构造函数记录属性,对应bean属性constructor-arg
79 */
80 @Nullable
81 private ConstructorArgumentValues constructorArgumentValues;
82
83 /**
84 * 普通属性集合
85 */
86 @Nullable
87 private MutablePropertyValues propertyValues;
88
89 /**
90 * 方法重写的持有者,记录lookup-method、replace-method元素
91 */
92 @Nullable
93 private MethodOverrides methodOverrides;
94
95 /**
96 * 初始化方法,对应bean属性init-method
97 */
98 @Nullable
99 private String initMethodName;
100
101 /**
102 * 销毁方法,对应bean属性destroy-method
103 */
104 @Nullable
105 private String destroyMethodName;
106
107 /**
108 * 是否执行init-method方法,程序设置
109 */
110 private boolean enforceInitMethod = true;
111
112 /**
113 * 是否执行destroy-method方法,程序设置
114 */
115 private boolean enforceDestroyMethod = true;
116
117 /**
118 * 是否是用户定义的而不是应用程序定义的。创建AOP的时候为true,程序设置
119 */
120 private boolean synthetic = false;
121
122 /**
123 * 定义这个bean的应用
124 * APPLICATION:用户
125 * INFRASTRUCTURE:完全内部使用,与用户无关
126 * SUPPORT:某些复杂配置的一部分
127 * 程序设置
128 */
129 private int role = BeanDefinition.ROLE_APPLICATION;
130
131 /**
132 * bean的描述信息
133 */
134 @Nullable
135 private String description;
136
137 /**
138 * bean定义的资源
139 */
140 @Nullable
141 private Resource resource;
二、注册解析BeanDefinition
org.springframework.beans.factory.xml包下的DefaultBeanDefinitionDocumentReader类中processBeanDefinition方法中的
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());这行代码进行注册操作
BeanDefinitionReaderUtils所在的包:org.springframework.beans.factory.support,看一下registerBeanDefinition方法的源码
1 /**
2 * Register the given bean definition with the given bean factory.
3 * @param definitionHolder the bean definition including name and aliases
4 * @param registry the bean factory to register with
5 * @throws BeanDefinitionStoreException if registration failed
6 */
7 public static void registerBeanDefinition(
8 BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
9 throws BeanDefinitionStoreException {
10
11 // Register bean definition under primary name.
12 // 使用beanName作为唯一标识
13 String beanName = definitionHolder.getBeanName();
14 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
15
16 // Register aliases for bean name, if any.
17 // 注册所有的别名
18 String[] aliases = definitionHolder.getAliases();
19 if (aliases != null) {
20 for (String alias : aliases) {
21 registry.registerAlias(beanName, alias);
22 }
23 }
24 }
通过上面的代码,可以看出,解析的BeanDefinition都会被注册到BeanDefinitionRegistry类型的registry实例中,而对于
BeanDefinition的注册分成了两部分,通过beanName的注册以及通过别名的注册
1、通过beanName的注册BeanDefinition
对于BeanDefinition的注册,或许我们都认为是将BeanDefinition直接放入map中,使用beanName作为key,确实spring是这么做的,
只不过,除此之外,还做了点别的事情
注意:这里spring中的BeanDefinitionRegistry是以接口形式存在的,它有三个实现类,分别是GenericApplicationContext、DefaultListableBeanFactory和
SimpleBeanDefinitionRegistry,其中SimpleBeanDefinitionRegistry类中的方法实现是没做任何事情,只是将其放入map中,其他两个实现类的处理逻辑是一样的
,只不过在GenericApplicationContext中创建了一个DefaultListableBeanFactory实例,来调用DefaultListableBeanFactory中的注册方法,所有,来看下
DefaultListableBeanFactory中registerBeanDefinition方法
org.springframework.beans.factory.support包下的DefaultListableBeanFactory类中:
1 @Override
2 public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
3 throws BeanDefinitionStoreException {
4
5 Assert.hasText(beanName, "Bean name must not be empty");
6 Assert.notNull(beanDefinition, "BeanDefinition must not be null");
7
8 if (beanDefinition instanceof AbstractBeanDefinition) {
9 try {
10 /**
11 * 注册前的最后一次验证,这里的校验不同于之前的XML文件校验<br>
12 * 主要是对于AbstractBeanDefinition属性中的methodOverrides校验<br>
13 * 验证methodOverrides是否与工厂方法共存或者methodOverrides对应的方法根本不存在
14 */
15 ((AbstractBeanDefinition) beanDefinition).validate();
16 }
17 catch (BeanDefinitionValidationException ex) {
18 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
19 "Validation of bean definition failed", ex);
20 }
21 }
22
23 BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
24 if (existingDefinition != null) {
25 if (!isAllowBeanDefinitionOverriding()) {
26 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
27 "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
28 "': There is already [" + existingDefinition + "] bound.");
29 }
30 else if (existingDefinition.getRole() < beanDefinition.getRole()) {
31 // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
32 if (logger.isWarnEnabled()) {
33 logger.warn("Overriding user-defined bean definition for bean '" + beanName +
34 "' with a framework-generated bean definition: replacing [" +
35 existingDefinition + "] with [" + beanDefinition + "]");
36 }
37 }
38 else if (!beanDefinition.equals(existingDefinition)) {
39 if (logger.isInfoEnabled()) {
40 ("Overriding bean definition for bean '" + beanName +
41 "' with a different definition: replacing [" + existingDefinition +
42 "] with [" + beanDefinition + "]");
43 }
44 }
45 else {
46 if (logger.isDebugEnabled()) {
47 logger.debug("Overriding bean definition for bean '" + beanName +
48 "' with an equivalent definition: replacing [" + existingDefinition +
49 "] with [" + beanDefinition + "]");
50 }
51 }
52 this.beanDefinitionMap.put(beanName, beanDefinition);
53 }
54 else {
55 // 已经创建至少一次的bean的名称
56 if (hasBeanCreationStarted()) {
57 // Cannot modify startup-time collection elements anymore (for stable iteration)
58 // 因为beanDefinitionMap是全局变量,这里肯定存在并发访问的问题
59 synchronized (this.beanDefinitionMap) {
60 // 处理beanName的存储问题
61 this.beanDefinitionMap.put(beanName, beanDefinition);
62 List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
63 updatedDefinitions.addAll(this.beanDefinitionNames);
64 updatedDefinitions.add(beanName);
65 this.beanDefinitionNames = updatedDefinitions;
66 if (this.manualSingletonNames.contains(beanName)) {
67 Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
68 updatedSingletons.remove(beanName);
69 this.manualSingletonNames = updatedSingletons;
70 }
71 }
72 }
73 // bean没有被创建过
74 else {
75 // Still in startup registration phase
76 // 注册beanDefinition并记录beanName
77 this.beanDefinitionMap.put(beanName, beanDefinition);
78 this.beanDefinitionNames.add(beanName);
79 this.manualSingletonNames.remove(beanName);
80 }
81 this.frozenBeanDefinitionNames = null;
82 }
83
84 if (existingDefinition != null || containsSingleton(beanName)) {
85 // 重置所有beanName对应的缓存
86 resetBeanDefinition(beanName);
87 }
88 }
注意:这里跟作者书中的代码有些出入,不知道难道是我下载的版本和作者不一样,不知道,反正总体的处理逻辑是一样的,只是这段代码是
处理的情况更加完善一些!
2、通过别名注册BeanDefinition
同样这个是在AliasRegistry接口中,BeanDefinitionRegistry是AliasRegistry的实现类,找到AliasRegistry类中registerAlias方法,进而找到实现类中方法实现
最终在org.springframework.core包下的SimpleAliasRegistry类中,源码如下:
1 @Override
2 public void registerAlias(String name, String alias) {
3 Assert.hasText(name, "'name' must not be empty");
4 Assert.hasText(alias, "'alias' must not be empty");
5 // aliasMap是全局变量,肯定存在并发问题
6 synchronized (this.aliasMap) {
7 // 如果alias与beanName相同的话,不记录alias
8 if (alias.equals(name)) {
9 this.aliasMap.remove(alias);
10 if (logger.isDebugEnabled()) {
11 logger.debug("Alias definition '" + alias + "' ignored since it points to same name");
12 }
13 }
14 else {
15 String registeredName = this.aliasMap.get(alias);
16 if (registeredName != null) {
17 if (registeredName.equals(name)) {
18 // An existing alias - no need to re-register
19 return;
20 }
21 // 如果alias别名不允许被覆盖则抛出异常
22 if (!allowAliasOverriding()) {
23 throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" +
24 name + "': It is already registered for name '" + registeredName + "'.");
25 }
26 if (logger.isInfoEnabled()) {
27 ("Overriding alias '" + alias + "' definition for registered name '" +
28 registeredName + "' with new target name '" + name + "'");
29 }
30 }
31 // 当A->B,存在时,若再次出现A->C->B则抛出异常
32 checkForAliasCircle(name, alias);
33 // 注册别名
34 this.aliasMap.put(alias, name);
35 if (logger.isDebugEnabled()) {
36 logger.debug("Alias definition '" + alias + "' registered for name '" + name + "'");
37 }
38 }
39 }
40 }
三、通知监听器解析及注册完成
通过代码getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
完成此工作,这里的实现只为扩展,当程序开发人员需要对注册BeanDefinition事件进行监听时可以通过注册监听器的方式
并将处理逻辑写在监听器中,目前spring中没有对此进行处理
四、alias标签的解析
alias标签,就是给bean起个别名,反正我是没用过这个,大概写一下吧!
用法如下:
1)<bean id="testBean" name="testBean2,testBean" class="com.test"></bean>
2)<bean id="testBean" class="com.test"></bean>
<alias name="testBean" alias="testBean2,testBean" />
源码解读:
org.springframework.beans.factory.xml包下DefaultBeanDefinitionDocumentReader类中的processAliasRegistration方法
1 /**
2 * Process the given alias element, registering the alias with the registry.
3 */
4 protected void processAliasRegistration(Element ele) {
5 // 获取beanName
6 String name = ele.getAttribute(NAME_ATTRIBUTE);
7 // 获取alias
8 String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
9 boolean valid = true;
10 if (!StringUtils.hasText(name)) {
11 getReaderContext().error("Name must not be empty", ele);
12 valid = false;
13 }
14 if (!StringUtils.hasText(alias)) {
15 getReaderContext().error("Alias must not be empty", ele);
16 valid = false;
17 }
18 if (valid) {
19 try {
20 // 注册alias
21 getReaderContext().getRegistry().registerAlias(name, alias);
22 }
23 catch (Exception ex) {
24 getReaderContext().error("Failed to register alias '" + alias +
25 "' for bean with name '" + name + "'", ele, ex);
26 }
27 // 注册别名后通知监听器做相应处理
28 getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));
29 }
30 }
五、import标签的解析
import标签实现了模块的划分,可以使得配置文件模块化,主要归结于import标签的功劳,
主要就是引入其他的
<import resource="customerContext.xml" />
<import resource="systemContext.xml" />
源码解读:
org.springframework.beans.factory.xml包下DefaultBeanDefinitionDocumentReader类中的importBeanDefinitionResource方法
1 /**
2 * Parse an "import" element and load the bean definitions
3 * from the given resource into the bean factory.
4 */
5 protected void importBeanDefinitionResource(Element ele) {
6 // 获取resource属性
7 String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
8 // 如果不存在resource属性则不做任何处理
9 if (!StringUtils.hasText(location)) {
10 getReaderContext().error("Resource location must not be empty", ele);
11 return;
12 }
13
14 // Resolve system properties: e.g. "${user.dir}"
15 // 解析系统属性 格式如:"${user.dir}"
16 location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
17
18 Set<Resource> actualResources = new LinkedHashSet<>(4);
19
20 // Discover whether the location is an absolute or relative URI
21 // 判断location是绝对路径还是相对路径
22 boolean absoluteLocation = false;
23 try {
24 absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
25 }
26 catch (URISyntaxException ex) {
27 // cannot convert to an URI, considering the location relative
28 // unless it is the well-known Spring prefix "classpath*:"
29 }
30
31 // Absolute or relative?
32 // 如果是绝对路径URI 则直接根据地址加载对应的配置文件
33 if (absoluteLocation) {
34 try {
35 int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
36 if (logger.isDebugEnabled()) {
37 logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]");
38 }
39 }
40 catch (BeanDefinitionStoreException ex) {
41 getReaderContext().error(
42 "Failed to import bean definitions from URL location [" + location + "]", ele, ex);
43 }
44 }
45 else {
46 // No URL -> considering resource location as relative to the current file.
47 // 如果是相对路径,则根据相对路径计算出绝对路径
48 try {
49 int importCount;
50 /**
51 * Resource存在多个实现类,如直接选中之后,快捷键Ctrl+T查看其实现类<br>
52 * 而每个Resource的createRelative实现都不一样,所以这里先尝试子类的方法进行尝试解析
53 */
54 Resource relativeResource = getReaderContext().getResource().createRelative(location);
55 if (relativeResource.exists()) {
56 importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
57 actualResources.add(relativeResource);
58 }
59 // 如果解析不成功,则使用默认的解析器ResourcePatternResolver进行解析,这个有点太复杂了,好多实现类,理不清楚!
60 else {
61 String baseLocation = getReaderContext().getResource().getURL().toString();
62 importCount = getReaderContext().getReader().loadBeanDefinitions(
63 StringUtils.applyRelativePath(baseLocation, location), actualResources);
64 }
65 if (logger.isDebugEnabled()) {
66 logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]");
67 }
68 }
69 catch (IOException ex) {
70 getReaderContext().error("Failed to resolve current resource location", ele, ex);
71 }
72 catch (BeanDefinitionStoreException ex) {
73 getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]",
74 ele, ex);
75 }
76 }
77 // 解析后进行监听器激活处理
78 Resource[] actResArray = actualResources.toArray(new Resource[0]);
79 getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
80 }