前言
在看Handler时看到了这么语段代码顿时就蒙了
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
});
经过指点知道这是回调函数,马上来补充一下~
什么是回调函数
回调函数,是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。 在Java中,指针即所谓的引用。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。 第一次看这知识点,是真的懵。下面看我拆解后逐步理解它的思路。
第0个版本
初代版本 我调用了你,在我调用你的方法里你又调用了我(回调)
public class ClassA {
public void a() {
System.out.println("执行了a方法");
ClassB b = new ClassB();
b.b();
}
public void backs(){
System.out.println("A:我就是A的回调函数!");
}
}
public class ClassB {
public void b() {
System.out.println("我执行了b");
System.out.println("B:我开始调用A的回调-->");
ClassA a = new ClassA();
a.backs();
System.out.println("B: <--我完成调用A的回调");
}
}
public class Main {
public static void main(String[] args) {
ClassA a = new ClassA();
a.a();
}
}
执行结果
执行了a方法
我执行了b
B:我开始调用A的回调-->
A:我就是A的回调函数!
B: <--我完成调用A的回调
第1个版本
演变一下把在B里创建的A,用对象的形式在A里调用时就带过去。 写一个回调用的接口
public class ClassA {
public void a() {
System.out.println("执行了a方法");
ClassB b = new ClassB();
b.b(this);
}
public void backs(){
System.out.println("A:我就是A的回调函数!");
}
}
public class ClassB {
public void b(ClassA a) {
System.out.println("我执行了b");
System.out.println("B:我开始调用A的回调-->");
a.backs();
System.out.println("B: <--我完成调用A的回调");
}
}
Main方法不用变 执行结果,执行结果不变
执行了a方法
我执行了b
B:我开始调用A的回调-->
A:我就是A的回调函数!
B: <--我完成调用A的回调
第2个版本
把第1个版本中的这个类换成接口Interface 创建一个接口
public interface Interface {
public void backs();
}
public class ClassA {
public void a() {
System.out.println("执行了a方法");
ClassB b = new ClassB();
b.b(new Interface() {
@Override
public void backs() {
System.out.println("A:我就是A的回调函数!");
}
});
}
}
public class ClassB {
public void b(Interface in) {
System.out.println("我执行了b");
System.out.println("B:我开始调用A的回调-->");
in.backs();
System.out.println("B: <--我完成调用A的回调");
}
}
Main依然不变 执行结果也不变
执行了a方法
我执行了b
B:我开始调用A的回调-->
A:我就是A的回调函数!
B: <--我完成调用A的回调
第3个版本
给接口加一个入参,让回调方法可以传参
public interface Interface {
public void backs(String n);
}
public class ClassA {
public void a() {
System.out.println("执行了a方法");
ClassB b = new ClassB();
b.b(new Interface() {
@Override
public void backs(String n) {
System.out.println("A:我就是A的回调函数!我打印:" + n);
}
});
}
}
public class ClassB {
public void b(Interface in) {
System.out.println("我执行了b");
System.out.println("B:我开始调用A的回调-->");
in.backs("《我是B传的参数》");
System.out.println("B: <--我完成调用A的回调");
}
}
执行结果
执行了a方法
我执行了b
B:我开始调用A的回调-->
A:我就是A的回调函数!我打印:《我是B传的参数》
B: <--我完成调用A的回调
第4个版本
给接口加个返回的参数
public interface Interface {
public String backs(String n);
}
public class ClassA {
public void a() {
System.out.println("执行了a方法");
ClassB b = new ClassB();
b.b(new Interface() {
@Override
public String backs(String n) {
System.out.println("A:我就是A的回调函数!我打印:" + n);
return "A:我就是A的回调函数!我打印:" + n + "的返回。";
}
});
}
}
public class ClassB {
public void b(Interface in) {
System.out.println("我执行了b");
System.out.println("B:我开始调用A的回调-->");
String backs = in.backs("《我是B传的参数》");
System.out.println("B:我收到了回调的结果:"+backs);
System.out.println("B: <--我完成调用A的回调");
}
}
执行结果
执行了a方法
我执行了b
B:我开始调用A的回调-->
A:我就是A的回调函数!我打印:《我是B传的参数》
B:我收到了回调的结果:A:我就是A的回调函数!我打印:《我是B传的参数》的返回。
B: <--我完成调用A的回调
第5个版本
public interface Interface {
public String backs(String n);
}
public class ClassA {
public void a() {
System.out.println("执行了a方法");
ClassB b = new ClassB();
String b1 = b.b(new Interface() {
@Override
public String backs(String n) {
System.out.println("A:我就是A的回调函数!我打印:" + n);
return "A:我就是A的回调函数!我打印:" + n + "的返回。";
}
});
System.out.println("A:执行完得到的结果:" + b1);
}
}
public class ClassB {
public String b(Interface in) {
System.out.println("我执行了b");
System.out.println("B:我开始调用A的回调-->");
String backs = in.backs("《我是B传的参数》");
System.out.println("B:我收到了回调的结果:"+backs + "<--我完成调用A的回调");
return "《我是B的返回》";
}
}
执行结果:
执行了a方法
我执行了b
B:我开始调用A的回调-->
A:我就是A的回调函数!我打印:《我是B传的参数》
B:我收到了回调的结果:A:我就是A的回调函数!我打印:《我是B传的参数》的返回。<--我完成调用A的回调
A:执行完得到的结果:《我是B的返回》
第6个版本
先声明回调函数,再使用
public class ClassA {
public void a() {
System.out.println("执行了a方法");
Interface in = (n -> {
System.out.println("A:我是直接使用回调接口,我接收的参数是:" + n);
return "我是回调的返回数据";
});
String backs = in.backs("我A,我是《in》的使用者");
System.out.println("backes:" + backs);
}
}
调用
public class Main {
public static void main(String[] args) {
ClassA a = new ClassA();
a.a();
}
}
执行结果
执行了a方法
A:我是直接使用回调接口,我接收的参数是:我A,我是《in》的使用者
backes:我是回调的返回数据
回头解析前言描述的问题
1. MethodIntrospector.selectMethods()
Map<Method, Set<Scheduled>> annotatedMethods = MethodIntrospector.selectMethods(targetClass,
(MethodIntrospector.MetadataLookup<Set<Scheduled>>) method -> {
Set<Scheduled> scheduledMethods = AnnotatedElementUtils.getMergedRepeatableAnnotations(
method, Scheduled.class, Schedules.class);
return (!scheduledMethods.isEmpty() ? scheduledMethods : null);
});
2. 抽象类MethodIntrospector
在这之前先看下这个回调的接口,这是MethodIntrospector类里的内部类
public abstract class MethodIntrospector {
public interface MetadataLookup<T> {
T inspect(Method method);
}
}
3. 方法selectMethods()
public static <T> Map<Method, T> selectMethods(Class<?> targetType, final MetadataLookup<T> metadataLookup) {
final 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);
}
handlerTypes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetType));
for (Class<?> currentHandlerType : handlerTypes) {
final Class<?> targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType);
ReflectionUtils.doWithMethods(currentHandlerType, method -> {
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
T result = metadataLookup.inspect(specificMethod);
if (result != null) {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
methodMap.put(specificMethod, result);
}
}
}, ReflectionUtils.USER_DECLARED_METHODS);
}
return methodMap;
}
4. 成员变量USER_DECLARED_METHODS
public static final MethodFilter USER_DECLARED_METHODS =
(method -> !method.isBridge() && !method.isSynthetic());
public abstract class ReflectionUtils {
public interface MethodFilter {
boolean matches(Method method);
}
}
5. 方法doWithMethods()
接selectMethods调用doWithMethods。对给定类和超类(或给定接口和超接口)的所有匹配方法执行给定的回调操作。
public static void doWithMethods(Class<?> clazz, MethodCallback mc, @Nullable MethodFilter mf) {
Method[] methods = getDeclaredMethods(clazz, false);
for (Method method : methods) {
if (mf != null && !mf.matches(method)) {
continue;
}
try {
mc.doWith(method);
}
catch (IllegalAccessException ex) {
throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
}
}
if (clazz.getSuperclass() != null && (mf != USER_DECLARED_METHODS || clazz.getSuperclass() != Object.class)) {
doWithMethods(clazz.getSuperclass(), mc, mf);
}
else if (clazz.isInterface()) {
for (Class<?> superIfc : clazz.getInterfaces()) {
doWithMethods(superIfc, mc, mf);
}
}
}
6. doWithMethods()方法里调用的getMappingForMethod()方法
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
info = typeInfo.combine(info);
}
String prefix = getPathPrefix(handlerType);
if (prefix != null) {
info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
}
}
return info;
}
看下效果更深刻
组合
组合完后的RequestMappingInfo
7. getMappingForMethod()方法里调用的createRequestMappingInfo()
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
RequestCondition<?> condition = (element instanceof Class ?
getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}
好奇,find什么样
实际我这个方法我怎么标记的?
调用创建RequestMappingInfo的构造
protected RequestMappingInfo createRequestMappingInfo(
RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {
RequestMappingInfo.Builder builder = RequestMappingInfo
.paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
.methods(requestMapping.method())
.params(requestMapping.params())
.headers(requestMapping.headers())
.consumes(requestMapping.consumes())
.produces(requestMapping.produces())
.mappingName(requestMapping.name());
if (customCondition != null) {
builder.customCondition(customCondition);
}
return builder.options(this.config).build();
}
创建完长这样
结言 所以最后的结果就是把这个类下所有方法标RequestMapping注解的方法以<Method,RequestMappingInfo>放入Map
全文完~
文文的博客,博学躬行。欢迎指正~
|