疯狂的橘猫-记Spring源码中lambda写法的理解
一,背景
在学习Spring获取bean对象的第二个getSingleton()方法,调用代码如下:
sharedInstance = getSingleton(beanName, () -> {
try {
// 创建Bean
return AbstractBeanFactory.this.createBean(beanName, mbd, args);
} catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
AbstractBeanFactory.this.destroySingleton(beanName);
throw ex;
}
});
跟踪代码的执行流程为:
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)
=》
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])
好了,问题来了,为什么lambda那里,写了过后,会调用到createBean()这里??
这个之前一直没看明白,然后我看到org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata(),里面ReflectionUtils.doWithLocalFields()的写法后明白了。
- ps 如果我写的理解有误,还请大神帮忙指正。
二,解释
通过一个代码模拟就可以看的很清楚,spring为什么要这样使用了。
public class FunctionIntf {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public FunctionIntf(String name) {
this.name = name;
}
public static void getPrint(Class<? extends FunctionIntf> clazz, Target target) {
Method[] declaredMethods = clazz.getDeclaredMethods();
System.out.println("getPrint方法的打印" + clazz.getName());
for (Method declaredMethod : declaredMethods) {
target.doWith(declaredMethod);
}
}
public static List<String> testPrint(String targetMethodName) {
FunctionIntf functionIntf = new FunctionIntf("Happy");
List<String> nameLists = new ArrayList<>();
// getPrint(functionIntf.getClass(), met -> {},这个方法的写法解读:
// 1.先不管lambda表达式,不管这个表达式有返回还是没有返回,都当成方法的入参
// 2.代码执行会先执行getPrint()这个方法
// 3.执行到getPrint()方法的 target.doWith(declaredMethod);这一句的时候
// 就是单纯的调用传入参数的target函数式接口的实现类中的doWith()方法
// 而这个实现的方法,就是再入参的时候定义了的。所以代码会执行到入参上面的写法
// 总的来说,先执行调用的方法,然后按照入参时lambda定义的代码方式在执行具体的实现
getPrint(functionIntf.getClass(), met -> {
String name = met.getName();
System.out.println("函数式接口获得的方法名称为:" + name);
if (targetMethodName.equals(name)) {
nameLists.add(name);
}
return null;
});
return nameLists;
}
public static void main(String[] args) {
List<String> list = FunctionIntf.testPrint("testPrint");
System.out.println(JSON.toJSONString(list));
}
@FunctionalInterface
interface Target {
Object doWith(Method args);
}
}