这个是接着上一篇来写,主要是这章内容比较多,还是分开来写吧!
一、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 logger.info("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 logger.info("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 }
来源:https://www.cnblogs.com/ssh-html/p/11180411.html