From 1d2448d1e9a66d4a6486983608195309764f0615 Mon Sep 17 00:00:00 2001 From: huifer Date: Sun, 27 Sep 2020 09:47:03 +0800 Subject: [PATCH] doc: Spring-MethodOverride --- README.md | 3 + docs/Spring/clazz/Spring-MethodOverride.md | 293 +++++++++++++++++++++ images/spring/MethodOverride.png | Bin 0 -> 12170 bytes 3 files changed, 296 insertions(+) create mode 100644 docs/Spring/clazz/Spring-MethodOverride.md create mode 100644 images/spring/MethodOverride.png diff --git a/README.md b/README.md index 1c8995e..4e85a65 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,9 @@ * [Spring 元数据](/docs/Spring/clazz/Spring-Metadata.md) * [Spring 条件接口](/docs/Spring/clazz/Spring-Conditional.md) +* [Spring MultiValueMap](/docs/Spring/clazz/Spring-MultiValueMap.md) +* [Spring MethodOverride](/docs/Spring/clazz/Spring-MethodOverride.md) + ### Spring5 新特性 diff --git a/docs/Spring/clazz/Spring-MethodOverride.md b/docs/Spring/clazz/Spring-MethodOverride.md new file mode 100644 index 0000000..36dc60e --- /dev/null +++ b/docs/Spring/clazz/Spring-MethodOverride.md @@ -0,0 +1,293 @@ +# Spring MethodOverride +- Author: [HuiFer](https://github.com/huifer) +- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read) + + +- `org.springframework.beans.factory.support.MethodOverride` + - `org.springframework.beans.factory.support.LookupOverride` + - `org.springframework.beans.factory.support.ReplaceOverride` +- `org.springframework.beans.factory.support.MethodOverrides` + + + +## MethodOverride +- MethodOverride 方法重载类 + + + +在`MethodOverride`定义了下面三个属性 + +1. 方法名称 +2. 是否重载 +3. 源 + +```java +public abstract class MethodOverride implements BeanMetadataElement { + + /** + * 方法名称 + */ + private final String methodName; + + /** + * 是否重载 + */ + private boolean overloaded = true; + + /** + * 源 + */ + @Nullable + private Object source; +} +``` + +- 定义了一个抽象方法, 交由子类实现 + +```java +public abstract boolean matches(Method method); +``` + + + + + +类图 + +![MethodOverride](/images/spring/MethodOverride.png) + + + +- 在Spring中有两种可以重写的机制(XML) + + 1. `lookup-method` 标签 + + ```xml + + ``` + + + + 2. `replaced-method` 标签 + + ```xml + + ``` + + + +相对应的两个类如类图所示 + + + + + +## LookupOverride + +- `org.springframework.beans.factory.support.LookupOverride` +- lookup-method 标签对应的实体对象 + +属性列表 + +1. beanName +2. method + +```java +@Nullable +private final String beanName; + +@Nullable +private Method method; +``` + + + +### matches + +比较方法 + +1. method是否直接相等 + 1. method 名称是否相同 + 2. 是否需要重载 +3. 是不是 ABSTRACT 方法 + 4. 参数列表长度是否等于0 + +```java + @Override + public boolean matches(Method method) { + if (this.method != null) { + // 通过 equals 判断 + return method.equals(this.method); + } + else { + // 1. method 名称是否相同 + // 2. 是否需要重载 + // 3. 是不是 ABSTRACT 方法 + // 4. 参数列表长度是否等于0 + return (method.getName().equals(getMethodName()) && (!isOverloaded() || + Modifier.isAbstract(method.getModifiers()) || method.getParameterCount() == 0)); + } + } + +``` + + + + + +## ReplaceOverride + +- `org.springframework.beans.factory.support.ReplaceOverride` + +```java +/** + * 实现 MethodReplacer 接口的bean name + * @see MethodReplacer + */ +private final String methodReplacerBeanName; + +/** + * 标签 arg-type 数据 + */ +private final List typeIdentifiers = new LinkedList<>(); +``` + + + +- 一个例子 + +```XML + + + + + String + + + + + + + + + +``` + + + +methodReplacerBeanName 对应`org.springframework.beans.factory.support.MethodReplacer` 的实现类 + +typeIdentifiers 对应标签 arg-type 的属性值 + + + +构造方法 + + + +```java +public ReplaceOverride(String methodName, String methodReplacerBeanName) { + super(methodName); + Assert.notNull(methodName, "Method replacer bean name must not be null"); + this.methodReplacerBeanName = methodReplacerBeanName; +} +``` + + + +methodName 通过父类进行设置 + + + + + +### matches + + + +```java +@Override +public boolean matches(Method method) { + // 方法名称是否相同 + if (!method.getName().equals(getMethodName())) { + return false; + } + // 是否重载 + if (!isOverloaded()) { + // Not overloaded: don't worry about arg type matching... + return true; + } + // If we get here, we need to insist on precise argument matching... + // 类型标识数量是否和参数列表是否不相同 + if (this.typeIdentifiers.size() != method.getParameterCount()) { + return false; + } + // 获取参数类型列表 + Class[] parameterTypes = method.getParameterTypes(); + for (int i = 0; i < this.typeIdentifiers.size(); i++) { + String identifier = this.typeIdentifiers.get(i); + // 判断 方法参数的类型是否在类型标识列表中 + if (!parameterTypes[i].getName().contains(identifier)) { + return false; + } + } + return true; +} +``` + + + + + + + +## MethodOverrides + +- `org.springframework.beans.factory.support.MethodOverrides` + +- 重载方法对象 + +- 存储所有重载的方法列表(set结构) + +```java + private final Set overrides = new CopyOnWriteArraySet<>(); +``` + + + + + +几个方法 + + + +1. 添加 MethodOverride + + ```java + public void addOverride(MethodOverride override) { + this.overrides.add(override); + } + + public void addOverrides(@Nullable MethodOverrides other) { + if (other != null) { + this.overrides.addAll(other.overrides); + } + } + ``` + +1. 获取 MethodOverride + + ```java + @Nullable + public MethodOverride getOverride(Method method) { + MethodOverride match = null; + for (MethodOverride candidate : this.overrides) { + if (candidate.matches(method)) { + match = candidate; + } + } + return match; + } + ``` \ No newline at end of file diff --git a/images/spring/MethodOverride.png b/images/spring/MethodOverride.png new file mode 100644 index 0000000000000000000000000000000000000000..1b2ec361be06a6cf5799fb560609fd66a709a30b GIT binary patch literal 12170 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 JdTQYJ-vD+^OzZ#v literal 0 HcmV?d00001