作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO
联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬
学习必须往深处挖,挖的越深,基础越扎实!
阶段1、深入多线程
阶段2、深入多线程设计模式
阶段3、深入juc源码解析
码哥源码部分
码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】
码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】
码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】
码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】
打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】
instantiateUsingFactoryMethod工厂方法实例化
上次讲实例提供器,讲了一篇,这次继续后面的,工厂方法实例化,比如bean
注解的也算。
先要获取构造器解析器,然后用工厂方法进行实例化。
protected BeanWrapper instantiateUsingFactoryMethod(
String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
}
ConstructorResolver
里面没啥逻辑,主要是保存beanFactory
。
public ConstructorResolver(AbstractAutowireCapableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
this.logger = beanFactory.getLogger();
}
instantiateUsingFactoryMethod真正创建的方法-分段1
这个方法很核心,他会根据工厂方法的是不是唯一来进行创建,如果唯一,就直接创建,不唯一的话还要进行所有方法获取,然后选出工厂方法,再处理,我们先讲简单的情况吧。先说第一段,先创建一个实例持有器,其实就是个包装类,然后从RootBeanDefinition
中获取factoryBeanName
,也就工厂方法,比如说bean
注解的方法就是,如果存在判断下是不是要创建自身,会报错,创建自身等于无限循环创建了。如果不是的话就获取factoryBean
即工厂实例,获取工厂类型,设置非静态的。如果获取不到工厂实例,说明是静态方法。
BeanWrapperImpl bw = new BeanWrapperImpl();//实例持有器
this.beanFactory.initBeanWrapper(bw);
Object factoryBean;//工厂实例
Class<?> factoryClass;//工厂类型
boolean isStatic;//是否是静态的,存在factoryBeanName表示是实例工厂,非静态方法,否则是静态的
//factoryBeanName,也就是工厂方法所属的类的简单名字,比如配置类,这里的factoryBean,不是FactoryBean接口
String factoryBeanName = mbd.getFactoryBeanName();
if (factoryBeanName != null) {//存在factoryBean
if (factoryBeanName.equals(beanName)) {//factoryBean创建出来的是工厂自身,会报异常,这样貌似等于无限递归创建了
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"factory-bean reference points back to the same bean definition");
}
factoryBean = this.beanFactory.getBean(factoryBeanName);//获得factoryBean
if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {//已经创建了
throw new ImplicitlyAppearedSingletonException();
}
factoryClass = factoryBean.getClass();
isStatic = false;//非静态的
}
else {//静态的方法,无factoryBean实例
// It's a static factory method on the bean class.
if (!mbd.hasBeanClass()) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"bean definition declares neither a bean class nor a factory-bean reference");
}
factoryBean = null;
factoryClass = mbd.getBeanClass();
isStatic = true;
}
instantiateUsingFactoryMethod真正创建的方法-分段2
准备好参数,尝试获取已经解析的数据,第一次都是空的。
Method factoryMethodToUse = null;//准备使用的工厂方法
ArgumentsHolder argsHolderToUse = null;//准备使用的参数包装器
Object[] argsToUse = null;//准备使用的参数
if (explicitArgs != null) {
argsToUse = explicitArgs;//如果有显示参数就使用这些参数
}
else {
Object[] argsToResolve = null;//解析出的参数
synchronized (mbd.constructorArgumentLock) {
factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {//如果有工厂方法,且构造函数已经解析了
// Found a cached factory method...
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
if (argsToResolve != null) {
argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
}
}
instantiateUsingFactoryMethod真正创建的方法-分段3
如果没解析过,就获取factoryClass
的用户定义类型,因为此时factoryClass
可能是CGLIB
动态代理类型,所以要获取用父类的类型。如果工厂方法是唯一的,就是没重载的,就获取解析的工厂方法,如果不为空,就添加到一个不可变列表里,如果为空的话,就要去 找出factoryClass
的以及父类的所有的方法 ,
进一步 找出方法修饰符一致且名字跟工厂方法名字相同的且是bean
注解的方法 ,并放入列表里。
if (factoryMethodToUse == null || argsToUse == null) {
// Need to determine the factory method...
// Try all methods with this name to see if they match the given arguments.
factoryClass = ClassUtils.getUserClass(factoryClass);//获取用户定义的类
//方法集合
List<Method> candidateList = null;
if (mbd.isFactoryMethodUnique) {//如果工厂方法唯一,没重载的
if (factoryMethodToUse == null) {
factoryMethodToUse = mbd.getResolvedFactoryMethod();//获取解析的工厂方法
}
if (factoryMethodToUse != null) {//存在的话,返回仅包含factoryMethodToUse的不可变列表
candidateList = Collections.singletonList(factoryMethodToUse);
}
}
if (candidateList == null) {//如果没找到工厂方法,可能有重载
candidateList = new ArrayList<>();
Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);//获取factoryClass以及父类的所有方法作为候选的方法
for (Method candidate : rawCandidates) {//过滤出修饰符一样,工厂方法名一样且是bean注解的方法
if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
candidateList.add(candidate);//如果isStatic修饰符一样且名字跟工厂方法名一样就添加
}
}
}
ClassUtils.getUserClass找出用户定义的类型
public static Class<?> getUserClass(Class<?> clazz) {
if (clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) {//如果包含CGLIB的名字符号,尝试获取父类
Class<?> superclass = clazz.getSuperclass();
if (superclass != null && superclass != Object.class) {
return superclass;
}
}
return clazz;
}
getCandidateMethods获取所有候选方法包括父类的
private Method[] getCandidateMethods(Class<?> factoryClass, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
return AccessController.doPrivileged((PrivilegedAction<Method[]>) () ->
(mbd.isNonPublicAccessAllowed() ?
ReflectionUtils.getAllDeclaredMethods(factoryClass) : factoryClass.getMethods()));
}
else {
return (mbd.isNonPublicAccessAllowed() ?
ReflectionUtils.getAllDeclaredMethods(factoryClass) : factoryClass.getMethods());
}
}
ReflectionUtils.getAllDeclaredMethods用反射获取方法
如果允许非Public
的方法,就获取所有申明的方法,包括父类的,否则就是Public
的方法,包括父类的,默认是允许的,我们直接看允许的就可以,原理一样的。
public static Method[] getAllDeclaredMethods(Class<?> leafClass) {
final List<Method> methods = new ArrayList<>(32);
doWithMethods(leafClass, methods::add);
return methods.toArray(EMPTY_METHOD_ARRAY);
}
public static void doWithMethods(Class<?> clazz, MethodCallback mc) {
doWithMethods(clazz, mc, null);
}
doWithMethods递归获取
递归获取所有的方法以及父类的,获取后执行mc.doWith(method)
方法,其实就是上面的methods::add
把方法添加到列表里,最后转换成数组返回。
public static void doWithMethods(Class<?> clazz, MethodCallback mc, @Nullable MethodFilter mf) {
// Keep backing up the inheritance hierarchy.
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);
}
}
}
剩下的下次讲吧。