4 getBean詳細な春の5.xソースの旅18
インスタンス化する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();
}
セグメント1 - instantiateUsingFactoryMethod方法は、実際に作成します
ユニークな場合は、この方法は非常にコアであり、彼はベースとなる工場を作成するための唯一の方法ではありません、我々は単純なケースについての話、再処理、直接、だけでなく、単語を作成するだけでなく、すべてのメソッドは、取得するために、その後、ファクトリメソッドを選択してくださいそれは。最初のデバイスを開催したインスタンスを作成し、私は最初の段落をお話しましょう、それが実際にラッパークラスで、そしてから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);
}
}
}
残りの次の言語を話します。
さて、今日ここに、私たちは自分自身の学習、限られた容量を理解し、偉大な神は見スプレーしないで、言い訳してください、助けの調査に希望と理解しています。