文章目录
前言
Spring 提供了MethodIntrospector 可以传入类以及筛选条件获取到符合该条件的方法集合,本文通过源码方式介绍其工作的内容。
一、MethodIntrospector 作用:
MethodIntrospector
是Spring Framework中的一个工具类,主要用于对类进行方法的分析和筛选。
具体来说,MethodIntrospector
类提供了一个selectMethods
静态方法,该方法可以根据传入的MethodFilter
接口实例或MetadataLookup
接口实例来选择类中符合条件的方法。MethodFilter
接口用于定义筛选条件,可以通过实现matches
方法决定哪些方法应该被选择,而MetadataLookup
接口则可以用来在选择方法时进行元数据查找。
通过MethodIntrospector
类,可以方便地对类中的方法进行筛选和分析,例如选择带有特定注解的方法、选择符合特定条件的方法等。这在编写通用性较高的框架或工具类时非常有用,可以提高代码的灵活性和可复用性。
二、 案例:
利用MethodIntrospector.selectMethods 获取类中标识了 MyAnnotation 注解的方法;
import com.xxl.job.core.handler.annotation.XxlJob;
import org.springframework.core.MethodIntrospector;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ReflectionUtils;
import java.lang.annotation.*;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;
public class MethodSelectorDemo {
public static void main(String[] args) {
// 定义一个目标类
Class<MyClass> clazz = MyClass.class;
// 使用MethodIntrospector.selectMethods方法,选择出不带参数的方法
Set<Method> selectedMethods = MethodIntrospector.selectMethods(clazz,
new ReflectionUtils.MethodFilter() {
@Override
public boolean matches(Method method) {
return AnnotationUtils.findAnnotation(method, MyAnnotation.class) != null;
}
});
// 遍历选择出的方法
for (Method selectedMethod : selectedMethods) {
System.out.println("Method with annotation: " + selectedMethod.getName());
}
Map<Method, MyAnnotation> annotatedMethods = MethodIntrospector.selectMethods(clazz,
new MethodIntrospector.MetadataLookup<MyAnnotation>() {
@Override
public MyAnnotation inspect(Method method) {
return AnnotatedElementUtils.findMergedAnnotation(method, MyAnnotation.class);
}
});
for (Map.Entry<Method, MyAnnotation> methodMyAnnotationEntry : annotatedMethods.entrySet()) {
System.out.println("Method with annotation: " + methodMyAnnotationEntry.getKey().getName());
}
}
static class MyClass {
@MyAnnotation("test")
public void doSomething() {
// do something
}
public void doAnotherThing(String param) {
// do another thing
}
}
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyAnnotation {
/**
* jobhandler name
*/
String value();
/**
* init handler, invoked when JobThread init
*/
String init() default "";
/**
* destroy handler, invoked when JobThread destroy
*/
String destroy() default "";
}
}
三、MethodIntrospector 源码内容
3.1 selectMethods 方法:
MethodIntrospector 提供了两个MethodIntrospector 来进行方法的筛选;
3.1.1 selectMethods(Class<?> targetType, MetadataLookup metadataLookup):
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.core;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
public final class MethodIntrospector {
private MethodIntrospector() {
}
/**
* targetType 某个类 class 对象
* MetadataLookup 实现了 MetadataLookup类下 inspect 方法的函数是接口
**/
public static <T> Map<Method, T> selectMethods(Class<?> targetType, MetadataLookup<T> metadataLookup) {
Map<Method, T> methodMap = new LinkedHashMap();
Set<Class<?>> handlerTypes = new LinkedHashSet();
Class<?> specificHandlerType = null;
// 判断是否是被代理的类
if (!Proxy.isProxyClass(targetType)) {
specificHandlerType = ClassUtils.getUserClass(targetType);
handlerTypes.add(specificHandlerType);
}
// 获取指定类targetType实现的所有接口的集合
handlerTypes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetType));
Iterator var5 = handlerTypes.iterator();
while(var5.hasNext()) {
// 遍历类
Class<?> currentHandlerType = (Class)var5.next();
Class<?> targetClass = specificHandlerType != null ? specificHandlerType : currentHandlerType;
// doWithMethods 遍历本类及其父类
ReflectionUtils.doWithMethods(currentHandlerType, (method) -> {
// 获取类中真正要去执行的方法
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
// inspect 接口调用
T result = metadataLookup.inspect(specificMethod);
if (result != null) {
// 如果result 不为null 则说明 条件匹配
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
// 获取方法并放入到 methodMap map 集合 key 为方法,value 为 inspect 方法返回的值
if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
methodMap.put(specificMethod, result);
}
}
}, ReflectionUtils.USER_DECLARED_METHODS);
}
// 返回map 集合
return methodMap;
}
@FunctionalInterface
public interface MetadataLookup<T> {
@Nullable
T inspect(Method var1);
}
}
改方法针对下面的调用:通过MethodIntrospector.MetadataLookup 重写 inspect 类
Map<Method, MyAnnotation> annotatedMethods = MethodIntrospector.selectMethods(clazz,
new MethodIntrospector.MetadataLookup<MyAnnotation>() {
@Override
public MyAnnotation inspect(Method method) {
return AnnotatedElementUtils.findMergedAnnotation(method, MyAnnotation.class);
}
});
for (Map.Entry<Method, MyAnnotation> methodMyAnnotationEntry : annotatedMethods.entrySet()) {
System.out.println("Method with annotation: " + methodMyAnnotationEntry.getKey().getName());
}
3.1.2 selectMethods(Class<?> targetType, ReflectionUtils.MethodFilter methodFilter):
public static Set<Method> selectMethods(Class<?> targetType, ReflectionUtils.MethodFilter methodFilter) {
// selectMethods 会调用到 selectMethods(Class<?> targetType, MetadataLookup<T> metadataLookup) 方法
/**
* 其中 method 部分:会被封装为 MetadataLookup 的函数式接口 { } 中的部分作为inspect 方法的实现逻辑;
* T result = metadataLookup.inspect(specificMethod) 调用inspect 会回调到 { } 中的部分
* 进而回调到 我我们自己业务中 覆盖的 matches 方法
* (method) -> {
return methodFilter.matches(method) ? Boolean.TRUE : null;
}
**/
return selectMethods(targetType, (method) -> {
return methodFilter.matches(method) ? Boolean.TRUE : null;
}).keySet();
}
改方法针对下面的调用:通过MethodIntrospector.selectMethods 重写 matches类
// 定义一个目标类
Class<MyClass> clazz = MyClass.class;
// 使用MethodIntrospector.selectMethods方法,选择出不带参数的方法
Set<Method> selectedMethods = MethodIntrospector.selectMethods(clazz,
new ReflectionUtils.MethodFilter() {
@Override
public boolean matches(Method method) {
return AnnotationUtils.findAnnotation(method, MyAnnotation.class) != null;
}
});
// 遍历选择出的方法
for (Method selectedMethod : selectedMethods) {
System.out.println("Method with annotation: " + selectedMethod.getName());
}
总结
本文对MethodIntrospector.selectMethods 获取类中符合条件的方法源码内容进行介绍。