diff --git a/docs/Mybatis/基础支持层/Mybatis-Cache.md b/docs/Mybatis/基础支持层/Mybatis-Cache.md index 512b1bc..f3c2f2f 100644 --- a/docs/Mybatis/基础支持层/Mybatis-Cache.md +++ b/docs/Mybatis/基础支持层/Mybatis-Cache.md @@ -1,6 +1,8 @@ # mybatis 缓存 - Author: [HuiFer](https://github.com/huifer) - Description: 该文介绍 mybatis Cache 源码 +- 源码阅读工程: [huifer-mybatis](https://github.com/huifer/javaBook-src/tree/old/mybatis-3) + - `org.apache.ibatis.cache.Cache` ```java public interface Cache { diff --git a/docs/Mybatis/基础支持层/Mybatis-Reflector.md b/docs/Mybatis/基础支持层/Mybatis-Reflector.md index d16dc09..764df15 100644 --- a/docs/Mybatis/基础支持层/Mybatis-Reflector.md +++ b/docs/Mybatis/基础支持层/Mybatis-Reflector.md @@ -1,6 +1,8 @@ # mybatis 反射 - Author: [HuiFer](https://github.com/huifer) - Description: 该文介绍 mybatis 反射相关类的源码 +- 源码阅读工程: [huifer-mybatis](https://github.com/huifer/javaBook-src/tree/old/mybatis-3) + ## addDefaultConstructor - mybatis 的反射相关内容在`org.apache.ibatis.reflection` 下存放. 本片主要讲解`org.apache.ibatis.reflection.Reflector`类, 先看一下该类的属性 diff --git a/docs/Mybatis/基础支持层/Mybatis-log.md b/docs/Mybatis/基础支持层/Mybatis-log.md index 335ed49..18d0c1a 100644 --- a/docs/Mybatis/基础支持层/Mybatis-log.md +++ b/docs/Mybatis/基础支持层/Mybatis-log.md @@ -1,6 +1,8 @@ # mybatis 日志源码 - Author: [HuiFer](https://github.com/huifer) - Description: 该文介绍 mybatis 日志相关源码 +- 源码阅读工程: [huifer-mybatis](https://github.com/huifer/javaBook-src/tree/old/mybatis-3) + ## 核心类 - `org.apache.ibatis.logging.Log` - `org.apache.ibatis.logging.LogFactory` diff --git a/docs/Mybatis/核心处理层/Mybatis-Alias.md b/docs/Mybatis/核心处理层/Mybatis-Alias.md index e0d4b38..316514a 100644 --- a/docs/Mybatis/核心处理层/Mybatis-Alias.md +++ b/docs/Mybatis/核心处理层/Mybatis-Alias.md @@ -1,6 +1,7 @@ # Mybatis Alias - Author: [HuiFer](https://github.com/huifer) - Description: 该文介绍 mybatis Alias 源码 +- 源码阅读工程: [huifer-mybatis](https://github.com/huifer/javaBook-src/tree/old/mybatis-3) - 源码位置 :`org.apache.ibatis.type.Alias` - 与 Alias 相关的一个方法`org.apache.ibatis.type.TypeAliasRegistry.registerAlias(java.lang.String, java.lang.Class)`(别名注册) diff --git a/docs/Mybatis/核心处理层/Mybatis-Cursor.md b/docs/Mybatis/核心处理层/Mybatis-Cursor.md index 249d9b2..e6744e3 100644 --- a/docs/Mybatis/核心处理层/Mybatis-Cursor.md +++ b/docs/Mybatis/核心处理层/Mybatis-Cursor.md @@ -1,6 +1,7 @@ # Mybatis Cursor - Author: [HuiFer](https://github.com/huifer) - Description: 该文介绍 mybatis Cursor 源码 +- 源码阅读工程: [huifer-mybatis](https://github.com/huifer/javaBook-src/tree/old/mybatis-3) ## Cursor - 源码位置:`org.apache.ibatis.cursor.Cursor` - 继承`Iterable`说明是一个迭代器,继承`Closeable`说明有一个东西需要关闭 diff --git a/docs/Mybatis/核心处理层/Mybatis-DataSource.md b/docs/Mybatis/核心处理层/Mybatis-DataSource.md index 2865813..bf90935 100644 --- a/docs/Mybatis/核心处理层/Mybatis-DataSource.md +++ b/docs/Mybatis/核心处理层/Mybatis-DataSource.md @@ -1,6 +1,8 @@ # Mybatis DataSource - Author: [HuiFer](https://github.com/huifer) - Description: 该文介绍 mybatis DataSource 源码 +- 源码阅读工程: [huifer-mybatis](https://github.com/huifer/javaBook-src/tree/old/mybatis-3) + - `org.apache.ibatis.datasource.DataSourceFactory` ```java /** diff --git a/docs/Mybatis/核心处理层/Mybatis-DyanmicSqlSourcce.md b/docs/Mybatis/核心处理层/Mybatis-DyanmicSqlSourcce.md index 2404a37..8a46af6 100644 --- a/docs/Mybatis/核心处理层/Mybatis-DyanmicSqlSourcce.md +++ b/docs/Mybatis/核心处理层/Mybatis-DyanmicSqlSourcce.md @@ -1,5 +1,6 @@ # Mybatis DyanmicSqlSourcce - Author: [HuiFer](https://github.com/huifer) +- 源码阅读工程: [huifer-mybatis](https://github.com/huifer/javaBook-src/tree/old/mybatis-3) - `org.apache.ibatis.scripting.xmltags.DynamicSqlSource` - `org.apache.ibatis.scripting.xmltags.DynamicContext.DynamicContext` diff --git a/docs/Mybatis/核心处理层/Mybatis-MapperMethod.md b/docs/Mybatis/核心处理层/Mybatis-MapperMethod.md index 21a6409..b0c6df7 100644 --- a/docs/Mybatis/核心处理层/Mybatis-MapperMethod.md +++ b/docs/Mybatis/核心处理层/Mybatis-MapperMethod.md @@ -2,6 +2,7 @@ - Author: [HuiFer](https://github.com/huifer) - Description: 该文介绍 mybatis MapperMethod 源码 - 源码地址: `org.apache.ibatis.binding.MapperMethod`,核心方法是`execute` +- 源码阅读工程: [huifer-mybatis](https://github.com/huifer/javaBook-src/tree/old/mybatis-3) ```java /** diff --git a/docs/Mybatis/核心处理层/Mybatis-MetaObject.md b/docs/Mybatis/核心处理层/Mybatis-MetaObject.md new file mode 100644 index 0000000..272a201 --- /dev/null +++ b/docs/Mybatis/核心处理层/Mybatis-MetaObject.md @@ -0,0 +1,112 @@ +# Mybatis MetaObject +- Author: [HuiFer](https://github.com/huifer) +- 源码阅读工程: [huifer-mybatis](https://github.com/huifer/javaBook-src/tree/old/mybatis-3) +- 源码位于:`org.apache.ibatis.reflection.MetaObject` +```java +/** + * @author Clinton Begin + */ +public class MetaObject { + + /** + * 原始的数据对象,初始化时的对象 + */ + private final Object originalObject; + /** + * 对象包装 + */ + private final ObjectWrapper objectWrapper; + /** + * object 工厂 + */ + private final ObjectFactory objectFactory; + /** + * object + */ + private final ObjectWrapperFactory objectWrapperFactory; + /** + * 反射工程 + */ + private final ReflectorFactory reflectorFactory; + + private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) { + this.originalObject = object; + this.objectFactory = objectFactory; + this.objectWrapperFactory = objectWrapperFactory; + this.reflectorFactory = reflectorFactory; + + // 根据object不同实例进行不同的实例化方式 + if (object instanceof ObjectWrapper) { + this.objectWrapper = (ObjectWrapper) object; + } else if (objectWrapperFactory.hasWrapperFor(object)) { + this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object); + } else if (object instanceof Map) { + this.objectWrapper = new MapWrapper(this, (Map) object); + } else if (object instanceof Collection) { + this.objectWrapper = new CollectionWrapper(this, (Collection) object); + } else { + this.objectWrapper = new BeanWrapper(this, object); + } + } + + public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) { + if (object == null) { + return SystemMetaObject.NULL_META_OBJECT; + } else { + return new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory); + } + } + + /** + * 获取value + * @param name 属性值名称 + * @return + */ + public Object getValue(String name) { + PropertyTokenizer prop = new PropertyTokenizer(name); + if (prop.hasNext()) { + MetaObject metaValue = metaObjectForProperty(prop.getIndexedName()); + if (metaValue == SystemMetaObject.NULL_META_OBJECT) { + // 判断是否是空的metaObject + return null; + } else { + return metaValue.getValue(prop.getChildren()); + } + } else { + return objectWrapper.get(prop); + } + } + + /** + * metaObject 设置属性值方法 + * {name:value} + * + * @param name 属性值名称 + * @param value 属性值 + */ + public void setValue(String name, Object value) { + PropertyTokenizer prop = new PropertyTokenizer(name); + if (prop.hasNext()) { + // 获取属性实例 + MetaObject metaValue = metaObjectForProperty(prop.getIndexedName()); + if (metaValue == SystemMetaObject.NULL_META_OBJECT) { + if (value == null) { + // value 空则返回 + // don't instantiate child path if value is null + return; + } else { + // 创建属性值 + metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory); + } + } + + metaValue.setValue(prop.getChildren(), value); + } else { + objectWrapper.set(prop, value); + } + } + + +} + +``` \ No newline at end of file diff --git a/docs/Mybatis/核心处理层/Mybatis-MethodSignature.md b/docs/Mybatis/核心处理层/Mybatis-MethodSignature.md index 6e378eb..1c83bc4 100644 --- a/docs/Mybatis/核心处理层/Mybatis-MethodSignature.md +++ b/docs/Mybatis/核心处理层/Mybatis-MethodSignature.md @@ -1,6 +1,7 @@ # MethodSignature - Author: [HuiFer](https://github.com/huifer) - Description: 该文介绍 mybatis MethodSignature 类 +- 源码阅读工程: [huifer-mybatis](https://github.com/huifer/javaBook-src/tree/old/mybatis-3) - `org.apache.ibatis.binding.MapperMethod.MethodSignature` ```java /** diff --git a/docs/Mybatis/核心处理层/Mybatis-ObjectWrapper.md b/docs/Mybatis/核心处理层/Mybatis-ObjectWrapper.md index 511d6c6..257216e 100644 --- a/docs/Mybatis/核心处理层/Mybatis-ObjectWrapper.md +++ b/docs/Mybatis/核心处理层/Mybatis-ObjectWrapper.md @@ -1,5 +1,6 @@ # Mybatis ObjectWrapper - Author: [HuiFer](https://github.com/huifer) +- 源码阅读工程: [huifer-mybatis](https://github.com/huifer/javaBook-src/tree/old/mybatis-3) - 源码位于: `org.apache.ibatis.reflection.wrapper.ObjectWrapper`‘ 类图: diff --git a/docs/Mybatis/核心处理层/Mybatis-ParamNameResolver.md b/docs/Mybatis/核心处理层/Mybatis-ParamNameResolver.md index 3b5d4ea..6c90204 100644 --- a/docs/Mybatis/核心处理层/Mybatis-ParamNameResolver.md +++ b/docs/Mybatis/核心处理层/Mybatis-ParamNameResolver.md @@ -1,6 +1,8 @@ # ParamNameResolver 源码解析 - Author: [HuiFer](https://github.com/huifer) - Description: 该文介绍 mybatis `@Param` 注解和`ParamNameResolver` +- 源码阅读工程: [huifer-mybatis](https://github.com/huifer/javaBook-src/tree/old/mybatis-3) + ## 源码 - `org.apache.ibatis.reflection.ParamNameResolver` ```java diff --git a/docs/Mybatis/核心处理层/Mybatis-SqlCommand.md b/docs/Mybatis/核心处理层/Mybatis-SqlCommand.md index 8680438..55c35b6 100644 --- a/docs/Mybatis/核心处理层/Mybatis-SqlCommand.md +++ b/docs/Mybatis/核心处理层/Mybatis-SqlCommand.md @@ -1,6 +1,7 @@ # sqlCommand - Author: [HuiFer](https://github.com/huifer) - Description: 该文介绍 mybatis sqlCommand类的源码 +- 源码阅读工程: [huifer-mybatis](https://github.com/huifer/javaBook-src/tree/old/mybatis-3) - `org.apache.ibatis.binding.MapperMethod.SqlCommand` ```java diff --git a/docs/Mybatis/核心处理层/Mybats-GenericTokenParser.md b/docs/Mybatis/核心处理层/Mybats-GenericTokenParser.md index c509486..6622c17 100644 --- a/docs/Mybatis/核心处理层/Mybats-GenericTokenParser.md +++ b/docs/Mybatis/核心处理层/Mybats-GenericTokenParser.md @@ -1,6 +1,7 @@ # GenericTokenParser - Author: [HuiFer](https://github.com/huifer) -- +- 源码阅读工程: [huifer-mybatis](https://github.com/huifer/javaBook-src/tree/old/mybatis-3) + ```java /** * Copyright 2009-2019 the original author or authors. diff --git a/docs/Spring/clazz/Spring-BeanDefinitionParserDelegate.md b/docs/Spring/clazz/Spring-BeanDefinitionParserDelegate.md new file mode 100644 index 0000000..d31d8a3 --- /dev/null +++ b/docs/Spring/clazz/Spring-BeanDefinitionParserDelegate.md @@ -0,0 +1,905 @@ +# Spring-BeanDefinitionParserDelegate +- Author: [HuiFer](https://github.com/huifer) +- 源码路径: `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate` +- 注意: 贴出的代码为当前类(`BeanDefinitionParserDelegate`)没有将其他的调用代码贴出,详细请看[huifer-srping](https://github.com/huifer/spring-framework). +- 该类的作用是将标签解析 + +- 下面这段代码是这个类的入口 + +```java + @Nullable + public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) { + // 获取id 属性 + String id = ele.getAttribute(ID_ATTRIBUTE); + // 获取 name 属性 + String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); + + // 别名列表 + List aliases = new ArrayList<>(); + if (StringUtils.hasLength(nameAttr)) { + String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); + aliases.addAll(Arrays.asList(nameArr)); + } + + // beanName = 中id的属性值 + String beanName = id; + if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { + beanName = aliases.remove(0); + if (logger.isTraceEnabled()) { + logger.trace("No XML 'id' specified - using '" + beanName + + "' as bean name and " + aliases + " as aliases"); + } + } + + if (containingBean == null) { + checkNameUniqueness(beanName, aliases, ele); + } + + // 创建对象 + AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); + if (beanDefinition != null) { + if (!StringUtils.hasText(beanName)) { + try { + if (containingBean != null) { + beanName = BeanDefinitionReaderUtils.generateBeanName( + beanDefinition, this.readerContext.getRegistry(), true); + } + else { + beanName = this.readerContext.generateBeanName(beanDefinition); + // Register an alias for the plain bean class name, if still possible, + // if the generator returned the class name plus a suffix. + // This is expected for Spring 1.2/2.0 backwards compatibility. + String beanClassName = beanDefinition.getBeanClassName(); + if (beanClassName != null && + beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && + !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) { + aliases.add(beanClassName); + } + } + if (logger.isTraceEnabled()) { + logger.trace("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); + return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); + } + + return null; + } +``` + +![image-20191231142829639](/image/spring/image-20191231142829639.png) + +该类大量的`parseXXX`开头的代码,这些方法都是对标签进行解析转换成具体的实体 + + + +### 测试用例 + +```xml + + + + + +``` + + + +## parseBeanDefinitionAttributes + +- 解析属性`scope`,`abstract`,`lazy-init` + +```java +public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, + @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) { + + if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) { + error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele); + } + 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()); + } + + if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) { + bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE))); + } + + String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE); + if (isDefaultValue(lazyInit)) { + lazyInit = this.defaults.getLazyInit(); + } + bd.setLazyInit(TRUE_VALUE.equals(lazyInit)); + + String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE); + bd.setAutowireMode(getAutowireMode(autowire)); + + if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) { + String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE); + bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS)); + } + + 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)); + } + + if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) { + bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE))); + } + + 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); + } + + 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); + } + + if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) { + bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE)); + } + if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) { + bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE)); + } + + return bd; + } +``` + + +![image-20191231162505748](/image/spring/image-20191231162505748.png) + +其他的标签也同样的方式**`getAttribute`**获取 + +思路: + +1. 判断是否有这个标签 + 1. 有直接获取,设置值 + 2. 没有跳过 + + + + +## parseMetaElements + +```java + /** + * 解析Meta 元素 + * {@code } => {@link BeanMetadataAttribute} + * Parse the meta elements underneath the given element, if any. + */ + public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) { + NodeList nl = ele.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + Node node = nl.item(i); + if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) { + Element metaElement = (Element) node; + // 获取 key 属性值 + String key = metaElement.getAttribute(KEY_ATTRIBUTE); + // 获取 value 属性值 + String value = metaElement.getAttribute(VALUE_ATTRIBUTE); + BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value); + attribute.setSource(extractSource(metaElement)); + attributeAccessor.addMetadataAttribute(attribute); + } + } + } + +``` + +![image-20191231164622063](/image/spring/image-20191231164622063.png) + + + + + +## parseLookupOverrideSubElements + +```java + /** + * 解析{@code } + * Parse lookup-override sub-elements of the given bean element. + */ + public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) { + NodeList nl = beanEle.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + Node node = nl.item(i); + if (isCandidateElement(node) && nodeNameEquals(node, LOOKUP_METHOD_ELEMENT)) { + Element ele = (Element) node; + String methodName = ele.getAttribute(NAME_ATTRIBUTE); + String beanRef = ele.getAttribute(BEAN_ELEMENT); + // 转换成JAVA对象 + LookupOverride override = new LookupOverride(methodName, beanRef); + override.setSource(extractSource(ele)); + overrides.addOverride(override); + } + } + } + +``` + +### 测试用例 + +```xml + + + + + + + + +``` + +![image-20191231165638975](/image/spring/image-20191231165638975.png) + + + + + + + +## parseReplacedMethodSubElements + +```java + /** + * {@code } + * Parse replaced-method sub-elements of the given bean element. + */ + public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) { + NodeList nl = beanEle.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + Node node = nl.item(i); + if (isCandidateElement(node) && nodeNameEquals(node, REPLACED_METHOD_ELEMENT)) { + Element replacedMethodEle = (Element) node; + String name = replacedMethodEle.getAttribute(NAME_ATTRIBUTE); + String callback = replacedMethodEle.getAttribute(REPLACER_ATTRIBUTE); + // 转换成JAVA对象 + ReplaceOverride replaceOverride = new ReplaceOverride(name, callback); + // Look for arg-type match elements. + // 参数解析 解析 + List argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, ARG_TYPE_ELEMENT); + for (Element argTypeEle : argTypeEles) { + String match = argTypeEle.getAttribute(ARG_TYPE_MATCH_ATTRIBUTE); + match = (StringUtils.hasText(match) ? match : DomUtils.getTextValue(argTypeEle)); + if (StringUtils.hasText(match)) { + replaceOverride.addTypeIdentifier(match); + } + } + replaceOverride.setSource(extractSource(replacedMethodEle)); + overrides.addOverride(replaceOverride); + } + } + } + +``` + +### 测试用例 + + 编写方法`dis` + +```java +public class Person { + private String name; + private Apple apple; + private Integer age; + + public void dis() { + System.out.println("dis"); + } +} +``` + +​ 编写一个替换`dis`方法的类 + +```java +public class Rc implements MethodReplacer { + @Override + public Object reimplement(Object obj, Method method, Object[] args) throws Throwable { + System.out.println("替换原来的方法"); + return null; + } +} +``` + +xml 配置 + +```java + + + +``` + +![image-20200101093742238](/image/spring/image-20200101093742238.png) + + + + + +## parseConstructorArgElements + +```java + public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) { + NodeList nl = beanEle.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + Node node = nl.item(i); + if (isCandidateElement(node) && nodeNameEquals(node, CONSTRUCTOR_ARG_ELEMENT)) { + parseConstructorArgElement((Element) node, bd); + } + } + } + +``` + +```java + /** + * 解析 constructor-arg 元素 + * {@code } + * Parse a constructor-arg element. + */ + public void parseConstructorArgElement(Element ele, BeanDefinition bd) { + String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE); + String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE); + String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); + // 判断是否存在 index 属性 + if (StringUtils.hasLength(indexAttr)) { + try { + int index = Integer.parseInt(indexAttr); + if (index < 0) { + error("'index' cannot be lower than 0", ele); + } + else { + try { + // ConstructorArgumentEntry 插入parseState + this.parseState.push(new ConstructorArgumentEntry(index)); + Object value = parsePropertyValue(ele, bd, null); + // 转换成JAVA对象 + ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value); + if (StringUtils.hasLength(typeAttr)) { + valueHolder.setType(typeAttr); + } + if (StringUtils.hasLength(nameAttr)) { + valueHolder.setName(nameAttr); + } + valueHolder.setSource(extractSource(ele)); + // 不允许重复指定相同参数 + if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) { + error("Ambiguous constructor-arg entries for index " + index, ele); + } + else { + bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder); + } + } + finally { + this.parseState.pop(); + } + } + } + catch (NumberFormatException ex) { + error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele); + } + } + else { + try { + this.parseState.push(new ConstructorArgumentEntry()); + Object value = parsePropertyValue(ele, bd, null); + ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value); + if (StringUtils.hasLength(typeAttr)) { + valueHolder.setType(typeAttr); + } + if (StringUtils.hasLength(nameAttr)) { + valueHolder.setName(nameAttr); + } + valueHolder.setSource(extractSource(ele)); + bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder); + } + finally { + this.parseState.pop(); + } + } + } + +``` + +```JAVA + /** + * Get the value of a property element. May be a list etc. + * Also used for constructor arguments, "propertyName" being null in this case. + */ + @Nullable + public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) { + String elementName = (propertyName != null ? + " element for property '" + propertyName + "'" : + " element"); + + // Should only have one child element: ref, value, list, etc. + NodeList nl = ele.getChildNodes(); + Element subElement = null; + for (int i = 0; i < nl.getLength(); i++) { + Node node = nl.item(i); + // 不处理 element 节点名称 = description 和 meta + if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) && + !nodeNameEquals(node, META_ELEMENT)) { + // Child element is what we're looking for. + if (subElement != null) { + error(elementName + " must not contain more than one sub-element", ele); + } + else { + subElement = (Element) node; + } + } + } + + // 判断是否存在 ref 属性 + boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE); + // 判断是否 value 属性 + boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE); + // 判断1: ref属性存在 value 属性 或者 ref 和 value 有一个存在并且有 下级节点 抛出异常 + if ((hasRefAttribute && hasValueAttribute) || + ((hasRefAttribute || hasValueAttribute) && subElement != null)) { + error(elementName + + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele); + } + + // 判断2: 存在 ref 返回 ref 的值 + if (hasRefAttribute) { + String refName = ele.getAttribute(REF_ATTRIBUTE); + if (!StringUtils.hasText(refName)) { + error(elementName + " contains empty 'ref' attribute", ele); + } + RuntimeBeanReference ref = new RuntimeBeanReference(refName); + ref.setSource(extractSource(ele)); + return ref; + } + // 判断3: 存在 value 返回 value 的值 + else if (hasValueAttribute) { + TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE)); + valueHolder.setSource(extractSource(ele)); + return valueHolder; + } + else if (subElement != null) { + // 下级标签解析 + return parsePropertySubElement(subElement, bd); + } + else { + // 没有抛出异常 + // Neither child element nor "ref" or "value" attribute found. + error(elementName + " must specify a ref or value", ele); + return null; + } + } + +``` + + + +### 测试用例 + +- 编辑构造函数 + + ```java + public class Person { + private String name; + private Apple apple; + private Integer age; + + public Person() { + } + + public Person(Integer age) { + this.age = age; + } + + ``` + +- 添加配置 + + ```xml + + + ``` + + + +![image-20200101100906778](/image/spring/image-20200101100906778.png) + + + +## parsePropertyElements + +```java +public void parsePropertyElements(Element beanEle, BeanDefinition bd) { + NodeList nl = beanEle.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + Node node = nl.item(i); + if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) { + parsePropertyElement((Element) node, bd); + } + } + } +``` + +```java + /** + * 解析 {@code } + * Parse a property element. + */ + public void parsePropertyElement(Element ele, BeanDefinition bd) { + String propertyName = ele.getAttribute(NAME_ATTRIBUTE); + if (!StringUtils.hasLength(propertyName)) { + error("Tag 'property' must have a 'name' attribute", ele); + return; + } + this.parseState.push(new PropertyEntry(propertyName)); + try { + if (bd.getPropertyValues().contains(propertyName)) { + error("Multiple 'property' definitions for property '" + propertyName + "'", ele); + return; + } + Object val = parsePropertyValue(ele, bd, propertyName); + // 转换JAVA 对象 + PropertyValue pv = new PropertyValue(propertyName, val); + parseMetaElements(ele, pv); + pv.setSource(extractSource(ele)); + bd.getPropertyValues().addPropertyValue(pv); + } + finally { + this.parseState.pop(); + } + } + +``` + +### 测试用例 + +xml + +```xml + + + +``` + + + +![image-20200101111755022](/image/spring/image-20200101111755022.png) + + + +## parseQualifierElements + +```java +public void parseQualifierElements(Element beanEle, AbstractBeanDefinition bd) { + NodeList nl = beanEle.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + Node node = nl.item(i); + if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ELEMENT)) { + parseQualifierElement((Element) node, bd); + } + } + } +``` + +```java + /** + * Parse a qualifier element. + */ + public void parseQualifierElement(Element ele, AbstractBeanDefinition bd) { + String typeName = ele.getAttribute(TYPE_ATTRIBUTE); + // 判断是否有类型 + if (!StringUtils.hasLength(typeName)) { + error("Tag 'qualifier' must have a 'type' attribute", ele); + return; + } + // 创建并且放入 parseState + this.parseState.push(new QualifierEntry(typeName)); + try { + AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(typeName); + qualifier.setSource(extractSource(ele)); + String value = ele.getAttribute(VALUE_ATTRIBUTE); + // 判断是否有值 + if (StringUtils.hasLength(value)) { + qualifier.setAttribute(AutowireCandidateQualifier.VALUE_KEY, value); + } + // 下级节点 + NodeList nl = ele.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + Node node = nl.item(i); + if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ATTRIBUTE_ELEMENT)) { + Element attributeEle = (Element) node; + // 获取 下级biao'qia + String attributeName = attributeEle.getAttribute(KEY_ATTRIBUTE); + String attributeValue = attributeEle.getAttribute(VALUE_ATTRIBUTE); + // 判断是否有 key 和 value + if (StringUtils.hasLength(attributeName) && StringUtils.hasLength(attributeValue)) { + // 转换成JAVA对象 + BeanMetadataAttribute attribute = new BeanMetadataAttribute(attributeName, attributeValue); + attribute.setSource(extractSource(attributeEle)); + qualifier.addMetadataAttribute(attribute); + } + else { + // 没有抛出异常 + error("Qualifier 'attribute' tag must have a 'name' and 'value'", attributeEle); + return; + } + } + } + bd.addQualifier(qualifier); + } + finally { + this.parseState.pop(); + } + } + +``` + + + +### 测试用例 + +- 编写一个注解 + +```java +/** + * 在spring-config.xml中配置 ,使用时通过 status + quality 来引入具体的bean + */ +@Target({ElementType.FIELD, ElementType.METHOD, + ElementType.TYPE, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +@Qualifier +public @interface PersonQualifier { + + String status(); + + String quality(); +} +``` + +```JAVA +public class PersonS { + private String personName; + + public String getPersonName() { + return personName; + } + + public void setPersonName(String personName) { + this.personName = personName; + } +} +``` + +```JAVA + +import org.springframework.beans.factory.annotation.Autowired; + +public class PersonService { + @Autowired +// @PersonQualifier(status = "status_teacher", quality = "quality_teacher") + @PersonQualifier(status = "status_student", quality = "quality_student") + private PersonS personS; + + public PersonS getPerson() { + return personS; + } + + public void setPerson(PersonS person) { + this.personS = person; + } +} +``` + +```JAVA +public class Student extends PersonS { + private String stdLocation; + + public String getStdLocation() { + return stdLocation; + } + + public void setStdLocation(String stdLocation) { + this.stdLocation = stdLocation; + } +} +``` + +```JAVA +public class Teacher extends PersonS { + private String subject; + + public String getSubject() { + return subject; + } + + public void setSubject(String subject) { + this.subject = subject; + } +} +``` + +```JAVA +public class QualifierSourceCode { + public static void main(String[] args) { + AbstractApplicationContext context = new ClassPathXmlApplicationContext("QualifierSourceCode-beans.xml"); + PersonService service = context.getBean(PersonService.class); + System.out.println(service.getPerson().getPersonName()); + context.close(); + } +} + +``` + +```XML + + + + + + + + + + + + + + + + + + + + + + + +``` + +![image-20200101155539501](/image/spring/image-20200101155539501.png) + + + + + +### Bean解析结果 + +![image-20200102083512005](/image/spring/image-20200102083512005.png) + + + + + +## importBeanDefinitionResource + +```JAVA + /** + * 解析{@code } 标签 + * Parse an "import" element and load the bean definitions + * from the given resource into the bean factory. + */ + protected void importBeanDefinitionResource(Element ele) { + // 获取 resource 属性 + String location = ele.getAttribute(RESOURCE_ATTRIBUTE); + // 是否有 resource 属性 + if (!StringUtils.hasText(location)) { + getReaderContext().error("Resource location must not be empty", ele); + return; + } + + // Resolve system properties: e.g. "${user.dir}" + // 获取系统环境,解析路径 + /** + * 1. getReaderContext() 获取{@link XmlReaderContext} + * 2. getEnvironment() 获取环境 + * 3. resolveRequiredPlaceholders(location) 解析占位符${...} + */ + location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location); + + // 资源存放集合 + Set actualResources = new LinkedHashSet<>(4); + + // Discover whether the location is an absolute or relative URI + // 相对路径 绝对路径的判断 + boolean absoluteLocation = false; + try { + // 判断是相对路径还是绝对路径 + absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute(); + } + catch (URISyntaxException ex) { + // cannot convert to an URI, considering the location relative + // unless it is the well-known Spring prefix "classpath*:" + } + + // Absolute or relative? + if (absoluteLocation) { + try { + // 获取import中的数量 + int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources); + if (logger.isTraceEnabled()) { + logger.trace("Imported " + importCount + " bean definitions from URL location [" + location + "]"); + } + } + catch (BeanDefinitionStoreException ex) { + getReaderContext().error( + "Failed to import bean definitions from URL location [" + location + "]", ele, ex); + } + } + else { + // No URL -> considering resource location as relative to the current file. + try { + int importCount; + // 本地地址 + Resource relativeResource = getReaderContext().getResource().createRelative(location); + if (relativeResource.exists()) { + // 此处调用方式和加载一个xml文件相同 + importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource); + + actualResources.add(relativeResource); + } + else { + String baseLocation = getReaderContext().getResource().getURL().toString(); + importCount = getReaderContext().getReader().loadBeanDefinitions( + StringUtils.applyRelativePath(baseLocation, location), actualResources); + } + if (logger.isTraceEnabled()) { + logger.trace("Imported " + importCount + " bean definitions from relative location [" + location + "]"); + } + } + catch (IOException ex) { + getReaderContext().error("Failed to resolve current resource location", ele, ex); + } + catch (BeanDefinitionStoreException ex) { + getReaderContext().error( + "Failed to import bean definitions from relative location [" + location + "]", ele, ex); + } + } + // 转换数组 + Resource[] actResArray = actualResources.toArray(new Resource[0]); + /*** + * fireImportProcessed()触发import事件, + * 并且通过{@link org.springframework.beans.factory.parsing.ReaderEventListener#importProcessed(ImportDefinition)} 宣布处理结果 + */ + getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele)); + } + +``` + + + +![image-20200102085031641](/image/spring/image-20200102085031641.png) + +![image-20200102091421516](/image/spring/image-20200102091421516.png) + + + diff --git a/docs/Spring/clazz/Spring-EntityResolver.md b/docs/Spring/clazz/Spring-EntityResolver.md new file mode 100644 index 0000000..e9012e3 --- /dev/null +++ b/docs/Spring/clazz/Spring-EntityResolver.md @@ -0,0 +1,158 @@ +# EntityResolver +- Author: [HuiFer](https://github.com/huifer) +- 源码阅读仓库: [huifer-spring](https://github.com/huifer/spring-framework) +- 源码路径: `org.xml.sax.EntityResolver`,非Spring类 + +## DelegatingEntityResolver#resolveEntity +- org.springframework.beans.factory.xml.DelegatingEntityResolver.resolveEntity +```java + @Override + @Nullable + public InputSource resolveEntity(@Nullable String publicId, @Nullable String systemId) + throws SAXException, IOException { + + if (systemId != null) { + if (systemId.endsWith(DTD_SUFFIX)) { + return this.dtdResolver.resolveEntity(publicId, systemId); + } + else if (systemId.endsWith(XSD_SUFFIX)) { + return this.schemaResolver.resolveEntity(publicId, systemId); + } + } + + // Fall back to the parser's default behavior. + return null; + } + +``` +- 上述这段代码是针对xml进行校验 +```xml + +``` +- 如上所示以`.xsd`结尾,应该执行` return this.schemaResolver.resolveEntity(publicId, systemId);`方法 +`http://www.springframework.org/schema/beans/spring-beans.xsd` +- `org.springframework.beans.factory.xml.PluggableSchemaResolver.resolveEntity` +## PluggableSchemaResolver#resolveEntity +```java + @Override + @Nullable + public InputSource resolveEntity(@Nullable String publicId, @Nullable String systemId) throws IOException { + if (logger.isTraceEnabled()) { + logger.trace("Trying to resolve XML entity with public id [" + publicId + + "] and system id [" + systemId + "]"); + } + + if (systemId != null) { + // 获取当前 systemId 对应的资源 + // spring-framework\spring-beans\src\main\resources\org\springframework\beans\factory\xml\spring-beans.xsd + String resourceLocation = getSchemaMappings().get(systemId); + if (resourceLocation == null && systemId.startsWith("https:")) { + // Retrieve canonical http schema mapping even for https declaration + resourceLocation = getSchemaMappings().get("http:" + systemId.substring(6)); + } + if (resourceLocation != null) { + // 加载 resourceLocation 转换成 Resource + Resource resource = new ClassPathResource(resourceLocation, this.classLoader); + try { + // 读取 + InputSource source = new InputSource(resource.getInputStream()); + source.setPublicId(publicId); + source.setSystemId(systemId); + if (logger.isTraceEnabled()) { + logger.trace("Found XML schema [" + systemId + "] in classpath: " + resourceLocation); + } + return source; + } + catch (FileNotFoundException ex) { + if (logger.isDebugEnabled()) { + logger.debug("Could not find XML schema [" + systemId + "]: " + resource, ex); + } + } + } + } + + // Fall back to the parser's default behavior. + return null; + } + +``` + +![image-20200108081404857](/images/spring//image-20200108081404857.png) + +![image-20200108081623427](/images/spring//image-20200108081623427.png) + +得到本地路径,后续直接返回读取资源 + +## BeansDtdResolver#resolveEntity + +创建一个Dtd的约束文件 + +```xml + + + + +``` + +```java + @Override + @Nullable + public InputSource resolveEntity(@Nullable String publicId, @Nullable String systemId) throws IOException { + if (logger.isTraceEnabled()) { + logger.trace("Trying to resolve XML entity with public ID [" + publicId + + "] and system ID [" + systemId + "]"); + } + + if (systemId != null && systemId.endsWith(DTD_EXTENSION)) { + int lastPathSeparator = systemId.lastIndexOf('/'); + int dtdNameStart = systemId.indexOf(DTD_NAME, lastPathSeparator); + if (dtdNameStart != -1) { + // 获取静态变量组装成文件名称(spring-beans.dtd) + String dtdFile = DTD_NAME + DTD_EXTENSION; + if (logger.isTraceEnabled()) { + logger.trace("Trying to locate [" + dtdFile + "] in Spring jar on classpath"); + } + try { + // 加载资源 + Resource resource = new ClassPathResource(dtdFile, getClass()); + InputSource source = new InputSource(resource.getInputStream()); + source.setPublicId(publicId); + source.setSystemId(systemId); + if (logger.isTraceEnabled()) { + logger.trace("Found beans DTD [" + systemId + "] in classpath: " + dtdFile); + } + return source; + } + catch (FileNotFoundException ex) { + if (logger.isDebugEnabled()) { + logger.debug("Could not resolve beans DTD [" + systemId + "]: not found in classpath", ex); + } + } + } + } + + // Fall back to the parser's default behavior. + return null; + } + +``` + + + + +- systemId `https://www.springframework.org/dtd/spring-beans-2.0.dtd` + +![image-20200108082335031](/images/spring//image-20200108082335031.png) + + +## 总结 + +- DelegatingEntityResolver#resolveEntity,是对xml文档的校验前置步骤,根据`dtd`和`xsd`加载本地资源文件 + `spring-framework\spring-beans\src\main\resources\org\springframework\beans\factory\xml\spring-beans.dtd` + `spring-framework\spring-beans\src\main\resources\org\springframework\beans\factory\xml\spring-beans.xsd` +- `PluggableSchemaResolver`负责加载`xsd`文件 +- `BeansDtdResolver`负责加载`dtd`文件 \ No newline at end of file diff --git a/docs/Spring/clazz/Spring-SimpleAliasRegistry.md b/docs/Spring/clazz/Spring-SimpleAliasRegistry.md new file mode 100644 index 0000000..144c88a --- /dev/null +++ b/docs/Spring/clazz/Spring-SimpleAliasRegistry.md @@ -0,0 +1,307 @@ +# Spring-SimpleAliasRegistry +- Author: [HuiFer](https://github.com/huifer) +- 源码阅读仓库: [huifer-spring](https://github.com/huifer/spring-framework) + +## AliasRegistry +- `SimpleAliasRegistry`继承`org.springframework.core.AliasRegistry` +```java +public interface AliasRegistry { + + /** + * Given a name, register an alias for it. + * 别名注册 + * + * @param name the canonical name + * @param alias the alias to be registered + * @throws IllegalStateException if the alias is already in use + * and may not be overridden + * @see SimpleAliasRegistry + * @see org.springframework.context.support.GenericApplicationContext + */ + void registerAlias(String name, String alias); + + /** + * Remove the specified alias from this registry. + * 别名移除 + * + * @param alias the alias to remove + * @throws IllegalStateException if no such alias was found + */ + void removeAlias(String alias); + + /** + * Determine whether this given name is defines as an alias + * (as opposed to the name of an actually registered component). + * 是不是别名 + * + * @param name the name to check + * @return whether the given name is an alias + */ + boolean isAlias(String name); + + /** + * Return the aliases for the given name, if defined. + * 从别名注册map中获取别名信息 + * + * @param name the name to check for aliases + * @return the aliases, or an empty array if none + */ + String[] getAliases(String name); + +} +``` +## SimpleAliasRegistry +```java +/** + * Simple implementation of the {@link AliasRegistry} interface. + * Serves as base class for + * {@link org.springframework.beans.factory.support.BeanDefinitionRegistry} + * implementations. + * + * @author Juergen Hoeller + * @since 2.5.2 + */ +public class SimpleAliasRegistry implements AliasRegistry { + + /** + * Logger available to subclasses. + */ + protected final Log logger = LogFactory.getLog(getClass()); + + /** + * Map from alias to canonical name. + * 存放别名的map(线程安全的), + * 结构: alias-> name + */ + private final Map aliasMap = new ConcurrentHashMap<>(16); + + + /** + * {@code } + * + * @param name the canonical name + * alias 标签的name属性 + * @param alias the alias to be registered + * alias 标签的alias属性 + */ + @Override + public void registerAlias(String name, String alias) { + Assert.hasText(name, "'name' must not be empty"); + Assert.hasText(alias, "'alias' must not be empty"); + synchronized (this.aliasMap) { + // 判断: 别名和名字是否相同 + if (alias.equals(name)) { + //相同在别名map中移除 + this.aliasMap.remove(alias); + if (logger.isDebugEnabled()) { + logger.debug("Alias definition '" + alias + "' ignored since it points to same name"); + } + } + else { + // 不相同 + // 从map对象中获取别名为alias的value + String registeredName = this.aliasMap.get(alias); + if (registeredName != null) { + // 判断map中是否有有一个别名和传入的name相同的内容 + if (registeredName.equals(name)) { + // An existing alias - no need to re-register + return; + } + if (!allowAliasOverriding()) { + throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" + + name + "': It is already registered for name '" + registeredName + "'."); + } + if (logger.isDebugEnabled()) { + logger.debug("Overriding alias '" + alias + "' definition for registered name '" + + registeredName + "' with new target name '" + name + "'"); + } + } + // 别名环检查 + checkForAliasCircle(name, alias); + // 放入 map 对象中 alias-> name + this.aliasMap.put(alias, name); + if (logger.isTraceEnabled()) { + logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'"); + } + } + } + } + + /** + * Return whether alias overriding is allowed. + * Default is {@code true}. + * 是否允许重写别名 + */ + protected boolean allowAliasOverriding() { + return true; + } + + /** + * Determine whether the given name has the given alias registered. + *

+ * 递归判断是否已经存在别名 + * + * @param name the name to check + * @param alias the alias to look for + * @since 4.2.1 + */ + public boolean hasAlias(String name, String alias) { + for (Map.Entry entry : this.aliasMap.entrySet()) { + // 获取key值 + String registeredName = entry.getValue(); + if (registeredName.equals(name)) { + String registeredAlias = entry.getKey(); + // 循环引用判断 + if (registeredAlias.equals(alias) || hasAlias(registeredAlias, alias)) { + return true; + } + } + } + return false; + } + + /** + * 别名移除 + * + * @param alias the alias to remove + */ + @Override + public void removeAlias(String alias) { + synchronized (this.aliasMap) { + // 判断是否移除成功 + String name = this.aliasMap.remove(alias); + if (name == null) { + throw new IllegalStateException("No alias '" + alias + "' registered"); + } + } + } + + /** + * 判断是否是一个别名,校验方式{@link org.springframework.core.SimpleAliasRegistry#aliasMap} 的key是否包含 + * + * @param name the name to check + * @return + */ + @Override + public boolean isAlias(String name) { + return this.aliasMap.containsKey(name); + } + + /** + * 获取别名列表 + * + * @param name the name to check for aliases + * @return + */ + @Override + public String[] getAliases(String name) { + List result = new ArrayList<>(); + synchronized (this.aliasMap) { + retrieveAliases(name, result); + } + return StringUtils.toStringArray(result); + } + + /** + * Transitively retrieve all aliases for the given name. + * 根据 name 获取别名 + * + * @param name the target name to find aliases for + * @param result the resulting aliases list + */ + private void retrieveAliases(String name, List result) { + // 循环获取 + this.aliasMap.forEach((alias, registeredName) -> { + if (registeredName.equals(name)) { + result.add(alias); + // 递归查询循环引用的别名 + retrieveAliases(alias, result); + } + }); + } + + /** + * Resolve all alias target names and aliases registered in this + * factory, applying the given StringValueResolver to them. + *

The value resolver may for example resolve placeholders + * in target bean names and even in alias names. + * + * @param valueResolver the StringValueResolver to apply + */ + public void resolveAliases(StringValueResolver valueResolver) { + Assert.notNull(valueResolver, "StringValueResolver must not be null"); + synchronized (this.aliasMap) { + Map aliasCopy = new HashMap<>(this.aliasMap); + aliasCopy.forEach((alias, registeredName) -> { + String resolvedAlias = valueResolver.resolveStringValue(alias); + String resolvedName = valueResolver.resolveStringValue(registeredName); + if (resolvedAlias == null || resolvedName == null || resolvedAlias.equals(resolvedName)) { + this.aliasMap.remove(alias); + } + else if (!resolvedAlias.equals(alias)) { + String existingName = this.aliasMap.get(resolvedAlias); + if (existingName != null) { + if (existingName.equals(resolvedName)) { + // Pointing to existing alias - just remove placeholder + this.aliasMap.remove(alias); + return; + } + throw new IllegalStateException( + "Cannot register resolved alias '" + resolvedAlias + "' (original: '" + alias + + "') for name '" + resolvedName + "': It is already registered for name '" + + registeredName + "'."); + } + checkForAliasCircle(resolvedName, resolvedAlias); + this.aliasMap.remove(alias); + this.aliasMap.put(resolvedAlias, resolvedName); + } + else if (!registeredName.equals(resolvedName)) { + this.aliasMap.put(alias, resolvedName); + } + }); + } + } + + /** + * Check whether the given name points back to the given alias as an alias + * in the other direction already, catching a circular reference upfront + * and throwing a corresponding IllegalStateException. + *

+ * 判断是否循环别名 + * + * @param name the candidate name + * @param alias the candidate alias + * @see #registerAlias + * @see #hasAlias + */ + protected void checkForAliasCircle(String name, String alias) { + if (hasAlias(alias, name)) { + throw new IllegalStateException("Cannot register alias '" + alias + + "' for name '" + name + "': Circular reference - '" + + name + "' is a direct or indirect alias for '" + alias + "' already"); + } + } + + /** + * Determine the raw name, resolving aliases to canonical names. + * + * @param name the user-specified name + * @return the transformed name + */ + public String canonicalName(String name) { + String canonicalName = name; + // Handle aliasing... + String resolvedName; + do { + resolvedName = this.aliasMap.get(canonicalName); + if (resolvedName != null) { + canonicalName = resolvedName; + } + } + while (resolvedName != null); + return canonicalName; + } + +} + +``` \ No newline at end of file diff --git a/images/spring/image-20191231142829639.png b/images/spring/image-20191231142829639.png new file mode 100644 index 0000000..6888d6e Binary files /dev/null and b/images/spring/image-20191231142829639.png differ diff --git a/images/spring/image-20191231162505748.png b/images/spring/image-20191231162505748.png new file mode 100644 index 0000000..ab94ce7 Binary files /dev/null and b/images/spring/image-20191231162505748.png differ diff --git a/images/spring/image-20191231164622063.png b/images/spring/image-20191231164622063.png new file mode 100644 index 0000000..18f1973 Binary files /dev/null and b/images/spring/image-20191231164622063.png differ diff --git a/images/spring/image-20191231165638975.png b/images/spring/image-20191231165638975.png new file mode 100644 index 0000000..020ad9d Binary files /dev/null and b/images/spring/image-20191231165638975.png differ diff --git a/images/spring/image-20200101093742238.png b/images/spring/image-20200101093742238.png new file mode 100644 index 0000000..3986373 Binary files /dev/null and b/images/spring/image-20200101093742238.png differ diff --git a/images/spring/image-20200101100906778.png b/images/spring/image-20200101100906778.png new file mode 100644 index 0000000..4aa23bb Binary files /dev/null and b/images/spring/image-20200101100906778.png differ diff --git a/images/spring/image-20200101111755022.png b/images/spring/image-20200101111755022.png new file mode 100644 index 0000000..7177f41 Binary files /dev/null and b/images/spring/image-20200101111755022.png differ diff --git a/images/spring/image-20200101155451199.png b/images/spring/image-20200101155451199.png new file mode 100644 index 0000000..dc73a7f Binary files /dev/null and b/images/spring/image-20200101155451199.png differ diff --git a/images/spring/image-20200101155539501.png b/images/spring/image-20200101155539501.png new file mode 100644 index 0000000..190f1b3 Binary files /dev/null and b/images/spring/image-20200101155539501.png differ diff --git a/images/spring/image-20200102083512005.png b/images/spring/image-20200102083512005.png new file mode 100644 index 0000000..0525f4b Binary files /dev/null and b/images/spring/image-20200102083512005.png differ diff --git a/images/spring/image-20200102085031641.png b/images/spring/image-20200102085031641.png new file mode 100644 index 0000000..8e382ea Binary files /dev/null and b/images/spring/image-20200102085031641.png differ diff --git a/images/spring/image-20200102091421516.png b/images/spring/image-20200102091421516.png new file mode 100644 index 0000000..c549cc0 Binary files /dev/null and b/images/spring/image-20200102091421516.png differ diff --git a/images/spring/image-20200108081404857.png b/images/spring/image-20200108081404857.png new file mode 100644 index 0000000..439c070 Binary files /dev/null and b/images/spring/image-20200108081404857.png differ diff --git a/images/spring/image-20200108081623427.png b/images/spring/image-20200108081623427.png new file mode 100644 index 0000000..19a4ef7 Binary files /dev/null and b/images/spring/image-20200108081623427.png differ diff --git a/images/spring/image-20200108082335031.png b/images/spring/image-20200108082335031.png new file mode 100644 index 0000000..2adee7a Binary files /dev/null and b/images/spring/image-20200108082335031.png differ diff --git a/images/springMVC/HandlerMapping组件.png b/images/springMVC/HandlerMapping组件.png index 48038ca..7703445 100644 Binary files a/images/springMVC/HandlerMapping组件.png and b/images/springMVC/HandlerMapping组件.png differ diff --git a/images/springMVC/SimpleUrlHandlerMapping的继承关系.png b/images/springMVC/SimpleUrlHandlerMapping的继承关系.png index 8c5ce0a..2c4d64d 100644 Binary files a/images/springMVC/SimpleUrlHandlerMapping的继承关系.png and b/images/springMVC/SimpleUrlHandlerMapping的继承关系.png differ