, MethodFilter> filters;
+
+ public ReflectiveMethodResolver() {
+ this.useDistance = true;
+ }
+
+ /**
+ * 此构造函数允许配置 ReflectiveMethodResolver,
+ * 使其使用距离计算来检查两个接近匹配中的更好的匹配
+ * (当存在多个匹配时)。使用距离计算旨在确保匹配更接近
+ * Java 编译器在考虑装箱/拆箱和方法候选人是否声明为
+ * 处理传入参数类型的类型(参数的类型)时会发生什么。
+ * @param useDistance 如果计算匹配时应使用距离计算,则为 {@code true};否则为 {@code false}
+ */
+ public ReflectiveMethodResolver(boolean useDistance) {
+ this.useDistance = useDistance;
+ }
+
+ /**
+ * 注册给定类型的方法过滤器。
+ * @param type 要过滤的类型
+ * @param filter 相应的方法过滤器,
+ * 如果要清除给定类型的任何过滤器,则为 {@code null}
+ */
+ public void registerMethodFilter(Class> type, @Nullable MethodFilter filter) {
+ if (this.filters == null) {
+ this.filters = new HashMap<>();
+ }
+ if (filter != null) {
+ this.filters.put(type, filter);
+ }
+ else {
+ this.filters.remove(type);
+ }
+ }
+
+ /**
+ * 在给定的上下文中,尝试定位目标对象上的适当方法,并返回一个方法执行器以供调用。
+ * 方法执行器将被缓存,但如果其状态过期,解析器将被再次调用。
+ *
+ * 在给定的上下文中,该方法确定可以处理指定参数的适当方法,并返回一个 {@link MethodExecutor} 对象,
+ * 该对象代表解析到的方法。如果找不到方法,则返回 {@code null}。
+ * @param context 当前的评估上下文
+ * @param targetObject 调用方法的对象
+ * @param name 方法名
+ * @param argumentTypes 方法的参数类型列表
+ * @return 可以调用方法的 MethodExecutor,如果找不到方法,则返回 null
+ * @throws AccessException 如果访问方法时发生错误
+ */
+ @Override
+ @Nullable
+ public MethodExecutor resolve(EvaluationContext context, Object targetObject, String name,
+ List argumentTypes) throws AccessException {
+ try {
+ // 获取类型转换器
+ TypeConverter typeConverter = context.getTypeConverter();
+ // 获取目标对象的类
+ Class> type = (targetObject instanceof Class ? (Class>) targetObject : targetObject.getClass());
+ // 获取目标对象上的所有方法
+ ArrayList methods = new ArrayList<>(getMethods(type, targetObject));
+
+ // 如果为该类型注册了过滤器,请调用它
+ MethodFilter filter = (this.filters != null ? this.filters.get(type) : null);
+ if (filter != null) {
+ List filtered = filter.filter(methods);
+ methods = (filtered instanceof ArrayList ? (ArrayList) filtered : new ArrayList<>(filtered));
+ }
+
+ // 将方法排序为合理的顺序
+ if (methods.size() > 1) {
+ methods.sort((m1, m2) -> {
+ int m1pl = m1.getParameterCount();
+ int m2pl = m2.getParameterCount();
+ // 变长参数方法放在最后
+ if (m1pl == m2pl) {
+ if (!m1.isVarArgs() && m2.isVarArgs()) {
+ return -1;
+ } else if (m1.isVarArgs() && !m2.isVarArgs()) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ return Integer.compare(m1pl, m2pl);
+ });
+ }
+
+ // 解析任何桥接方法
+ for (int i = 0; i < methods.size(); i++) {
+ methods.set(i, BridgeMethodResolver.findBridgedMethod(methods.get(i)));
+ }
+
+ // 删除重复的方法(由于解析的桥接方法可能导致)
+ Set methodsToIterate = new LinkedHashSet<>(methods);
+
+ Method closeMatch = null;
+ int closeMatchDistance = Integer.MAX_VALUE;
+ Method matchRequiringConversion = null;
+ boolean multipleOptions = false;
+
+ // 遍历方法,查找适合的方法
+ for (Method method : methodsToIterate) {
+ if (method.getName().equals(name)) {
+ int paramCount = method.getParameterCount();
+ List paramDescriptors = new ArrayList<>(paramCount);
+ // 构造方法参数类型描述符列表
+ for (int i = 0; i < paramCount; i++) {
+ paramDescriptors.add(new TypeDescriptor(new MethodParameter(method, i)));
+ }
+ ReflectionHelper.ArgumentsMatchInfo matchInfo = null;
+ if (method.isVarArgs() && argumentTypes.size() >= (paramCount - 1)) {
+ // 处理变长参数
+ matchInfo = ReflectionHelper.compareArgumentsVarargs(paramDescriptors, argumentTypes, typeConverter);
+ } else if (paramCount == argumentTypes.size()) {
+ // 检查参数是否匹配
+ matchInfo = ReflectionHelper.compareArguments(paramDescriptors, argumentTypes, typeConverter);
+ }
+ if (matchInfo != null) {
+ if (matchInfo.isExactMatch()) {
+ return new ReflectiveMethodExecutor(method);
+ } else if (matchInfo.isCloseMatch()) {
+ if (this.useDistance) {
+ // 计算匹配的距离
+ int matchDistance = ReflectionHelper.getTypeDifferenceWeight(paramDescriptors, argumentTypes);
+ if (closeMatch == null || matchDistance < closeMatchDistance) {
+ // 保存更好的匹配
+ closeMatch = method;
+ closeMatchDistance = matchDistance;
+ }
+ } else {
+ // 如果没有更好的匹配,将其视为接近匹配
+ if (closeMatch == null) {
+ closeMatch = method;
+ }
+ }
+ } else if (matchInfo.isMatchRequiringConversion()) {
+ if (matchRequiringConversion != null) {
+ multipleOptions = true;
+ }
+ matchRequiringConversion = method;
+ }
+ }
+ }
+ }
+ // 返回找到的方法执行器
+ if (closeMatch != null) {
+ return new ReflectiveMethodExecutor(closeMatch);
+ } else if (matchRequiringConversion != null) {
+ if (multipleOptions) {
+ // 如果有多个匹配,则抛出异常
+ throw new SpelEvaluationException(SpelMessage.MULTIPLE_POSSIBLE_METHODS, name);
+ }
+ return new ReflectiveMethodExecutor(matchRequiringConversion);
+ } else {
+ return null;
+ }
+ } catch (EvaluationException ex) {
+ // 解析方法时出现异常
+ throw new AccessException("Failed to resolve method", ex);
+ }
+ }
+
+
+ private Set getMethods(Class> type, Object targetObject) {
+ if (targetObject instanceof Class) {
+ Set result = new LinkedHashSet<>();
+ // 添加这些方法,以便在类型上可调用静态方法:例如 Float.valueOf(..)
+ Method[] methods = getMethods(type);
+ for (Method method : methods) {
+ if (Modifier.isStatic(method.getModifiers())) {
+ result.add(method);
+ }
+ }
+ // 还从 java.lang.Class 本身公开方法
+ Collections.addAll(result, getMethods(Class.class));
+ return result;
+ }
+ else if (Proxy.isProxyClass(type)) {
+ Set result = new LinkedHashSet<>();
+ // 公开接口方法(不是代理声明的重写)以便适当的变长参数内省
+ for (Class> ifc : type.getInterfaces()) {
+ Method[] methods = getMethods(ifc);
+ for (Method method : methods) {
+ if (isCandidateForInvocation(method, type)) {
+ result.add(method);
+ }
+ }
+ }
+ return result;
+ }
+ else {
+ Set result = new LinkedHashSet<>();
+ Method[] methods = getMethods(type);
+ for (Method method : methods) {
+ if (isCandidateForInvocation(method, type)) {
+ result.add(method);
+ }
+ }
+ return result;
+ }
+ }
+
+ /**
+ * 返回此类型的方法集。默认实现返回给定类型的 {@link Class#getMethods()} 的结果,
+ * 但子类可以重写以更改结果,例如指定在其他地方声明的静态方法。
+ * @param type 要返回方法的类
+ * @since 3.1.1
+ */
+ protected Method[] getMethods(Class> type) {
+ return type.getMethods();
+ }
+
+ /**
+ * 确定给定的 {@code Method} 是否是在给定目标类的实例上进行方法解析的候选方法。
+ * 默认实现将任何方法都视为候选方法,即使对于 {@link Object} 基类的静态方法
+ * 和非用户声明的方法也是如此。
+ * @param method 要评估的方法
+ * @param targetClass 正在内省的具体目标类
+ * @since 4.3.15
+ */
+ protected boolean isCandidateForInvocation(Method method, Class> targetClass) {
+ return true;
+ }
+
+}
+```
+
+### 六、主要实现
+
+1. **DataBindingMethodResolver**
+
+ + 是用于数据绑定环境的方法解析器,支持根据数据绑定的规则解析方法,例如 Spring 数据绑定框架中的规则,并可能使用更高级的技术如 Spring DataBinding,根据数据绑定的配置和元数据来查找适当的方法。
+
+2. **ReflectiveMethodResolver**
+
+ + 是基于反射机制的通用方法解析器,通过反射检查目标对象的方法,根据方法名和参数类型进行匹配,适用于大多数的 Java 对象和方法的解析,不需要特殊的配置或规则,只需要基于 Java 反射来解析方法即可。
+
+### 七、最佳实践
+
+使用Spring Expression Language(SpEL)来调用自定义对象(`MyBean`)中的方法。首先,通过SpEL表达式解析器创建一个解析器和一个上下文对象,然后实例化一个`MyBean`对象并将其设置为上下文中的变量。接着,创建一个SpEL表达式,调用`MyBean`对象的`add`方法,并传入两个参数。最后,将表达式与上下文关联,并计算表达式的值,即调用`MyBean`对象的方法并获取结果。
+
+```java
+public class MethodResolverDemo {
+
+ public static void main(String[] args) {
+ // 创建一个SpEL表达式解析器
+ ExpressionParser parser = new SpelExpressionParser();
+
+ StandardEvaluationContext context = new StandardEvaluationContext();
+
+ // 在 MyBean 中定义的方法将被 SpEL 表达式调用
+ MyBean myBean = new MyBean();
+ context.setVariable("myBean", myBean);
+
+ // 创建一个 SpEL 表达式,调用 MyBean 中的方法
+ SpelExpression expression = (SpelExpression) parser.parseExpression("#myBean.add(10, 5)");
+
+ // 为表达式设置上下文,并计算结果
+ int result = (int) expression.getValue(context);
+
+ // 打印输出实例化的MyBean对象
+ System.out.println("result = " + result);
+ }
+}
+```
+
+ `MyBean` 类定义了一个简单的方法 `add`,它接受两个整数参数,并返回它们的和。
+
+```java
+public class MyBean {
+ public int add(int a, int b) {
+ return a + b;
+ }
+}
+```
+
+运行结果,在 `MethodResolverDemo` 中调用了 `MyBean` 对象的 `add` 方法,并传入了两个参数(10 和 5),所以计算结果为 10 + 5 = 15。
+
+```java
+result = 15
+```
+
+### 八、与其他组件的关系
+
+1. **StandardEvaluationContext**
+
+ + `MethodResolver` 接口通常与 `StandardEvaluationContext` 类一起使用。`StandardEvaluationContext` 提供了 SpEL 表达式的运行时上下文,其中可以存储变量、函数等信息,并且可以设置自定义的方法解析器,其中就包括了 `MethodResolver` 接口的实现类。
+
+2. **ExpressionParser**
+
+ + `ExpressionParser` 接口用于解析 SpEL 表达式。在 SpEL 中,可以使用 `ExpressionParser` 实现类来解析表达式,例如 `SpelExpressionParser`。在解析 SpEL 表达式时,通常需要提供一个 `EvaluationContext`,这个上下文中可能会包含一个或多个 `MethodResolver`,用于解析表达式中的方法调用。
+
+3. **MethodExecutor**
+
+ + `MethodResolver` 接口的 `resolve` 方法返回一个 `MethodExecutor` 对象,它用于执行解析到的方法。`MethodExecutor` 是一个接口,它定义了执行方法的方法 `execute`,具体的执行逻辑由其实现类提供。
+
+4. **ReflectiveMethodResolver** & **DataBindingMethodResolver**
+
+ + 这两个类是 `MethodResolver` 接口的实现类,分别用于基于反射和数据绑定环境下的方法解析。它们与 `MethodResolver` 接口的关系在于,它们实现了 `MethodResolver` 接口,并提供了具体的方法解析逻辑。在使用 SpEL 表达式时,可以选择性地使用这两个类中的一个或者自定义其他的方法解析器来解析方法调用。
+
+### 九、常见问题
+
+1. **如何自定义方法解析器?**
+
+ - 可以实现 `MethodResolver` 接口,并覆写其中的 `resolve` 方法来定义自定义的方法解析逻辑。然后将这个自定义的方法解析器注册到 `StandardEvaluationContext` 中。
+
+2. **方法解析器的优先级如何确定?**
+
+ - 在 `StandardEvaluationContext` 中,可以注册多个方法解析器,它们的解析顺序由注册的顺序决定。解析时会按照注册的顺序逐个调用方法解析器,直到找到匹配的方法。
+
+3. **如何处理方法重载?**
+
+ - 当方法重载时,`MethodResolver` 需要根据传入的参数类型列表来确定最适合的方法。在解析方法调用时,会尝试匹配所有可能的方法,并根据参数类型的匹配程度来选择最佳的匹配。
+
+4. **如何处理变长参数方法?**
+
+ - 变长参数方法(例如使用 `...` 定义的参数)在方法解析中需要特殊处理。方法解析器需要检查传入的参数数量和类型是否与方法定义匹配,并正确处理变长参数的情况。
+
+5. **如何处理方法参数的类型转换?**
+
+ - 当方法参数的类型与传入参数的类型不完全匹配时,可能需要进行类型转换。方法解析器可以使用注册的类型转换器来进行必要的参数类型转换。
+
+6. **如何处理桥接方法?**
+
+ - 桥接方法是 Java 泛型中的一个特殊情况,可能会导致方法重载或者匹配错误。方法解析器需要正确处理桥接方法,以确保找到正确的方法进行调用。
+
+7. **如何处理方法的静态调用?**
+
+ - 当调用静态方法时,需要在方法解析器中考虑到静态方法的情况。方法解析器需要正确处理静态方法的调用,以确保可以找到并调用正确的静态方法。
\ No newline at end of file
diff --git a/spring-spel/spring-spel-methodResolver/pom.xml b/spring-spel/spring-spel-methodResolver/pom.xml
new file mode 100644
index 0000000..13728b0
--- /dev/null
+++ b/spring-spel/spring-spel-methodResolver/pom.xml
@@ -0,0 +1,14 @@
+
+
+
+ com.xcs.spring
+ spring-spel
+ 0.0.1-SNAPSHOT
+
+
+ 4.0.0
+ spring-spel-methodResolver
+
+
\ No newline at end of file
diff --git a/spring-spel/spring-spel-methodResolver/src/main/java/com/xcs/spring/MethodResolverDemo.java b/spring-spel/spring-spel-methodResolver/src/main/java/com/xcs/spring/MethodResolverDemo.java
new file mode 100644
index 0000000..e082b3c
--- /dev/null
+++ b/spring-spel/spring-spel-methodResolver/src/main/java/com/xcs/spring/MethodResolverDemo.java
@@ -0,0 +1,33 @@
+package com.xcs.spring;
+
+import org.springframework.expression.ExpressionParser;
+import org.springframework.expression.spel.standard.SpelExpression;
+import org.springframework.expression.spel.standard.SpelExpressionParser;
+import org.springframework.expression.spel.support.StandardEvaluationContext;
+
+/**
+ * @author xcs
+ * @date 2024年3月12日11:28:47
+ **/
+public class MethodResolverDemo {
+
+ public static void main(String[] args) {
+ // 创建一个SpEL表达式解析器
+ ExpressionParser parser = new SpelExpressionParser();
+
+ StandardEvaluationContext context = new StandardEvaluationContext();
+
+ // 在 MyBean 中定义的方法将被 SpEL 表达式调用
+ MyBean myBean = new MyBean();
+ context.setVariable("myBean", myBean);
+
+ // 创建一个 SpEL 表达式,调用 MyBean 中的方法
+ SpelExpression expression = (SpelExpression) parser.parseExpression("#myBean.add(10, 5)");
+
+ // 为表达式设置上下文,并计算结果
+ int result = (int) expression.getValue(context);
+
+ // 打印输出实例化的MyBean对象
+ System.out.println("result = " + result);
+ }
+}
diff --git a/spring-spel/spring-spel-methodResolver/src/main/java/com/xcs/spring/MyBean.java b/spring-spel/spring-spel-methodResolver/src/main/java/com/xcs/spring/MyBean.java
new file mode 100644
index 0000000..d93fbdd
--- /dev/null
+++ b/spring-spel/spring-spel-methodResolver/src/main/java/com/xcs/spring/MyBean.java
@@ -0,0 +1,7 @@
+package com.xcs.spring;
+
+public class MyBean {
+ public int add(int a, int b) {
+ return a + b;
+ }
+}
diff --git a/spring-spel/spring-spel-propertyAccessor/pom.xml b/spring-spel/spring-spel-propertyAccessor/pom.xml
index 67a2419..0fa1040 100644
--- a/spring-spel/spring-spel-propertyAccessor/pom.xml
+++ b/spring-spel/spring-spel-propertyAccessor/pom.xml
@@ -2,19 +2,13 @@
- 4.0.0
com.xcs.spring
spring-spel
0.0.1-SNAPSHOT
+ 4.0.0
spring-spel-propertyAccessor
-
- 11
- 11
- UTF-8
-
-
\ No newline at end of file
diff --git a/spring-spel/spring-spel-typeLocator/README.md b/spring-spel/spring-spel-typeLocator/README.md
new file mode 100644
index 0000000..0b6ea1f
--- /dev/null
+++ b/spring-spel/spring-spel-typeLocator/README.md
@@ -0,0 +1,229 @@
+## TypeLocator
+
+- [TypeLocator](#TypeLocator)
+ - [一、基本信息](#一基本信息)
+ - [二、知识储备](#二知识储备)
+ - [三、基本描述](#三基本描述)
+ - [四、主要功能](#四主要功能)
+ - [五、接口源码](#五接口源码)
+ - [六、主要实现](#六主要实现)
+ - [七、最佳实践](#七最佳实践)
+ - [八、与其他组件的关系](#八与其他组件的关系)
+ - [九、常见问题](#九常见问题)
+
+### 一、基本信息
+
+✒️ **作者** - Lex 📝 **博客** - [掘金](https://juejin.cn/user/4251135018533068/posts) 📚 **源码地址** - [github](https://github.com/xuchengsheng/spring-reading)
+
+### 二、知识储备
+
+1. **Spring 表达式语言(SpEL)**
+
+ + 了解 SpEL 的基础语法和用法是必要的,因为 `TypeLocator` 接口通常用于 SpEL 中,用于动态获取类型信息。
+
+2. **反射(Reflection)**
+
+ + 了解 Java 中的反射机制,包括 `Class` 类、`Method` 类、`Field` 类等,因为 `TypeLocator` 接口通常需要使用反射来查找和操作类型信息。
+
+3. **设计模式**
++ 熟悉常见的设计模式,如工厂模式、策略模式等,这些设计模式在实现 `TypeLocator` 接口时可能会有所应用。
+
+### 三、基本描述
+
+`TypeLocator` 接口是 Spring Framework 中的关键接口之一,用于动态定位类型信息,在 Spring 表达式语言(SpEL)等场景中扮演重要角色,通过提供方法如`findType(String typeName)`和`hasType(String typeName)`,允许 SpEL 在运行时动态获取和检查类型信息,增强了 Spring 应用程序的灵活性和功能性。
+
+### 四、主要功能
+
+1. **查找类型信息**
+
+ + 通过 `findType(String typeName)` 方法,根据给定的类型名称查找对应的类型信息,使得 SpEL 在运行时能够动态获取所需类型的信息。
+
+2. **检查类型是否存在**
+
+ + 通过 `hasType(String typeName)` 方法,可以检查是否存在给定名称的类型。这对于确定能否解析给定的类型很有用。
+
+### 五、接口源码
+
+`TypeLocator` 接口定义了一种用于定位类型信息的机制,其中包含一个抽象方法 `findType(String typeName)`,用于根据给定的类型名称查找对应的类型,并返回表示该类型的 `Class` 对象。
+
+```java
+/**
+ * 实现此接口的类应能够定位类型。它们可以使用自定义的 {@link ClassLoader},
+ * 和/或以任何方式处理常见的包前缀(例如 {@code java.lang})。
+ *
+ *
参见 {@link org.springframework.expression.spel.support.StandardTypeLocator}
+ * 以获取示例实现。
+ *
+ * @author Andy Clement
+ * @since 3.0
+ */
+@FunctionalInterface
+public interface TypeLocator {
+
+ /**
+ * 根据名称查找类型。名称可以是完全限定的,也可以不是(例如 {@code String} 或 {@code java.lang.String})。
+ * @param typeName 要定位的类型
+ * @return 表示该类型的 {@code Class} 对象
+ * @throws EvaluationException 如果查找类型时出现问题
+ */
+ Class> findType(String typeName) throws EvaluationException;
+
+}
+
+```
+
+`StandardTypeLocator` 是一个简单的实现类,实现了 `TypeLocator` 接口,用于根据给定的类型名称查找对应的类型信息。它支持使用上下文 ClassLoader 和注册的导入前缀来定位类型,当找不到类型时会尝试使用注册的导入前缀来定位。
+
+```java
+/**
+ * 一个简单的 {@link TypeLocator} 实现,它使用上下文 ClassLoader(或设置在其上的任何 ClassLoader)。
+ * 它支持'well-known'包:如果找不到类型,则会尝试注册的导入来定位它。
+ *
+ * @author Andy Clement
+ * @author Juergen Hoeller
+ * @since 3.0
+ */
+public class StandardTypeLocator implements TypeLocator {
+
+ @Nullable
+ private final ClassLoader classLoader;
+
+ private final List knownPackagePrefixes = new ArrayList<>(1);
+
+ /**
+ * 为默认的 ClassLoader(通常是线程上下文 ClassLoader)创建一个 StandardTypeLocator。
+ */
+ public StandardTypeLocator() {
+ this(ClassUtils.getDefaultClassLoader());
+ }
+
+ /**
+ * 为给定的 ClassLoader 创建一个 StandardTypeLocator。
+ * @param classLoader 要委托的 ClassLoader
+ */
+ public StandardTypeLocator(@Nullable ClassLoader classLoader) {
+ this.classLoader = classLoader;
+ // 类似于编写常规的 Java 代码,默认只知道 java.lang
+ registerImport("java.lang");
+ }
+
+ /**
+ * 注册一个新的导入前缀,用于搜索未限定类型时使用。
+ * 期望的格式类似于 "java.lang"。
+ * @param prefix 要注册的前缀
+ */
+ public void registerImport(String prefix) {
+ this.knownPackagePrefixes.add(prefix);
+ }
+
+ /**
+ * 从此定位器的导入列表中删除指定的前缀。
+ * @param prefix 要移除的前缀
+ */
+ public void removeImport(String prefix) {
+ this.knownPackagePrefixes.remove(prefix);
+ }
+
+ /**
+ * 返回此 StandardTypeLocator 注册的所有导入前缀的列表。
+ * @return 注册的导入前缀列表
+ */
+ public List getImportPrefixes() {
+ return Collections.unmodifiableList(this.knownPackagePrefixes);
+ }
+
+ /**
+ * 查找(可能是未限定的)类型引用 - 首先使用原始类型名称,然后如果找不到类型名称,则尝试任何注册的前缀。
+ * @param typeName 要定位的类型
+ * @return 类型的 Class 对象
+ * @throws EvaluationException 如果找不到类型
+ */
+ @Override
+ public Class> findType(String typeName) throws EvaluationException {
+ String nameToLookup = typeName;
+ try {
+ return ClassUtils.forName(nameToLookup, this.classLoader);
+ }
+ catch (ClassNotFoundException ey) {
+ // 在放弃之前尝试任何已注册的前缀
+ }
+ for (String prefix : this.knownPackagePrefixes) {
+ try {
+ nameToLookup = prefix + '.' + typeName;
+ return ClassUtils.forName(nameToLookup, this.classLoader);
+ }
+ catch (ClassNotFoundException ex) {
+ // 可能是另一个前缀
+ }
+ }
+ throw new SpelEvaluationException(SpelMessage.TYPE_NOT_FOUND, typeName);
+ }
+}
+```
+
+### 六、主要实现
+
+1. **StandardTypeLocator**
+
+ + `StandardTypeLocator` 类是实现了 `TypeLocator` 接口的简单实现,用于在给定类型名称时定位类型信息。
+
+### 七、最佳实践
+
+使用 Spring 表达式语言(SpEL)来获取类型信息。通过解析不同的表达式,包括获取特定类型的 Class 对象和比较不同类型的枚举值,展示了 SpEL 在类型定位和类型比较方面的功能。
+
+```java
+public class TypeLocatorDemo {
+ public static void main(String[] args) {
+ // 创建一个SpEL表达式解析器
+ ExpressionParser parser = new SpelExpressionParser();
+
+ // 解析表达式获取 Date 类的 Class 对象
+ Class dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class.class);
+ System.out.println("dateClass = " + dateClass);
+
+ // 解析表达式获取 String 类的 Class 对象
+ Class stringClass = parser.parseExpression("T(String)").getValue(Class.class);
+ System.out.println("stringClass = " + stringClass);
+
+ // 解析表达式比较两个 RoundingMode 枚举值的大小
+ boolean trueValue = parser.parseExpression("T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR").getValue(Boolean.class);
+ System.out.println("trueValue = " + trueValue);
+ }
+}
+```
+
+运行结果,成功获取了 `java.util.Date` 和 `java.lang.String` 的 Class 对象,并且对 `java.math.RoundingMode` 枚举类型进行了比较,结果为真。
+
+```properties
+dateClass = class java.util.Date
+stringClass = class java.lang.String
+trueValue = true
+```
+
+### 八、与其他组件的关系
+
+1. **Class**
+
+ + `Class` 类是 Java 反射中的重要类,用于表示类的运行时信息。它提供了获取类的名称、方法、字段等信息的方法。在 `TypeLocator` 接口的实现中,可能会使用 `Class` 类来表示获取到的类信息。
+
+2. **ClassLoader**
+
+ + `ClassLoader` 类是 Java 中的一个关键类,用于动态加载 Java 类文件到 Java 虚拟机中。它负责加载类文件并生成对应的 `Class` 对象。在与 `TypeLocator` 接口相关的实现中,可能会使用 `ClassLoader` 来加载和获取类信息。
+
+3. **StandardTypeLocator**
+
+ + `TypeLocator`接口的实现类,是一个简单的类型定位器,通常用于在 SpEL 中查找类型信息。
+
+### 九、常见问题
+
+1. **如何实现自定义的 TypeLocator?**
+
+ - 我们可能会想要根据特定需求实现自定义的 `TypeLocator` 接口,以满足特定的类型定位需求。在这种情况下,需要实现 `findType(String typeName)` 方法,根据给定的类型名称查找对应的类型信息,并根据需求处理类型的查找逻辑。
+
+2. **如何处理不同的类型查找策略?**
+
+ - 在某些情况下,可能需要根据不同的情况使用不同的类型查找策略。例如,可能需要根据不同的包前缀使用不同的类型查找逻辑,或者需要根据不同的条件动态切换类型查找策略。在这种情况下,我们需要考虑如何设计和实现灵活的类型查找策略。
+
+3. **如何处理类型查找失败的情况?**
+
+ - 当无法找到指定类型时,需要考虑如何处理类型查找失败的情况。可能的处理方式包括抛出异常、返回默认值或者尝试其他类型查找策略。我们需要根据具体情况选择合适的处理方式,并确保用户能够得到明确的反馈。
\ No newline at end of file
diff --git a/spring-spel/spring-spel-typeLocator/pom.xml b/spring-spel/spring-spel-typeLocator/pom.xml
new file mode 100644
index 0000000..81b21c4
--- /dev/null
+++ b/spring-spel/spring-spel-typeLocator/pom.xml
@@ -0,0 +1,14 @@
+
+
+
+ com.xcs.spring
+ spring-spel
+ 0.0.1-SNAPSHOT
+
+
+ 4.0.0
+ spring-spel-typeLocator
+
+
\ No newline at end of file
diff --git a/spring-spel/spring-spel-typeLocator/src/main/java/com/xcs/spring/TypeLocatorDemo.java b/spring-spel/spring-spel-typeLocator/src/main/java/com/xcs/spring/TypeLocatorDemo.java
new file mode 100644
index 0000000..31418d7
--- /dev/null
+++ b/spring-spel/spring-spel-typeLocator/src/main/java/com/xcs/spring/TypeLocatorDemo.java
@@ -0,0 +1,23 @@
+package com.xcs.spring;
+
+import org.springframework.expression.ExpressionParser;
+import org.springframework.expression.spel.standard.SpelExpressionParser;
+
+public class TypeLocatorDemo {
+ public static void main(String[] args) {
+ // 创建一个SpEL表达式解析器
+ ExpressionParser parser = new SpelExpressionParser();
+
+ // 解析表达式获取 Date 类的 Class 对象
+ Class dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class.class);
+ System.out.println("dateClass = " + dateClass);
+
+ // 解析表达式获取 String 类的 Class 对象
+ Class stringClass = parser.parseExpression("T(String)").getValue(Class.class);
+ System.out.println("stringClass = " + stringClass);
+
+ // 解析表达式比较两个 RoundingMode 枚举值的大小
+ boolean trueValue = parser.parseExpression("T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR").getValue(Boolean.class);
+ System.out.println("trueValue = " + trueValue);
+ }
+}