引数はinstantiateBeanをインスタンス化しないと二十から四getBeanは10コンストラクタを詳細春5.xのソース旅
デフォルトコンストラクタを呼び出すinstantiateBean
以前は普通のインスタンスが作成されている場合、それが唯一のデフォルトコンストラクタは、デフォルトコンストラクタを行う方法で見てみましょうすることができ、おそらく多く、そこにオーバーロードされ、使用することができますコンストラクタを探します、と述べました彼は比較的簡単ですので。
実際には、そこにインスタンス化戦略を取得することで、その後、instantiate
インスタンス化、言った戦略の前でCglibSubclassingInstantiationStrategy
はなく、一般的または親と、注射した場合にのみ作業を意志SimpleInstantiationStrategy
さんinstantiate
。
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
getInstantiationStrategy().instantiate(mbd, beanName, parent),
getAccessControlContext());
}
else {
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
BeanWrapper bw = new BeanWrapperImpl(beanInstance);//包装成BeanWrapper
initBeanWrapper(bw);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}
SimpleInstantiationStrategy的インスタンス化
メソッドをオーバーロードされたことが判明した場合は、必要なCGLIB
インスタンスを直接にデフォルトコンストラクタを取得していない場合は、動的エージェントに。すでに述べたようにインスタンス化そしてので、ここであなたが彼の直接施工方法を得ることができ、引数なしのコンストラクタであることが判明し、されています。
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
if (!bd.hasMethodOverrides()) {//无lookup重载的方法
Constructor<?> constructorToUse;
synchronized (bd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
final Class<?> clazz = bd.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
constructorToUse = AccessController.doPrivileged(
(PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
}
else {
constructorToUse = clazz.getDeclaredConstructor();
}
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
return BeanUtils.instantiateClass(constructorToUse);
}
else {//有lookup重载的话要用CGLIB动态代理了
// Must generate CGLIB subclass.
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
々BeanUtils的instantiateClass
ここでは、コンストラクタを呼び出す例ですが、見てみましょうことはないがKotlin
、そして一般的であり、JAVA
作成したインスタンス化するコンストラクタメソッド。
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
Assert.notNull(ctor, "Constructor must not be null");
try {
ReflectionUtils.makeAccessible(ctor);
if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {
return KotlinDelegate.instantiateClass(ctor, args);
}
else {
Class<?>[] parameterTypes = ctor.getParameterTypes();
Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters");
Object[] argsWithDefaultValues = new Object[args.length];
for (int i = 0 ; i < args.length; i++) {//获得参数
if (args[i] == null) {
Class<?> parameterType = parameterTypes[i];
argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null);
}
else {
argsWithDefaultValues[i] = args[i];
}
}
return ctor.newInstance(argsWithDefaultValues);
}
}
catch (InstantiationException ex) {
throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
}
catch (IllegalAccessException ex) {
throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
}
catch (IllegalArgumentException ex) {
throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
}
catch (InvocationTargetException ex) {
throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
}
}
CglibSubclassingInstantiationStrategy的instantiateWithMethodInjection
あなたが発見した場合はloolup
アノテーション付きメソッドを、それがこのメソッドを呼び出します。
@Override
protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
return instantiateWithMethodInjection(bd, beanName, owner, null);
}
@Override
protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
@Nullable Constructor<?> ctor, Object... args) {
// Must generate CGLIB subclass...
return new CglibSubclassCreator(bd, owner).instantiate(ctor, args);
}
CglibSubclassCreator的インスタンス化
まず作成GCLIB
ブースターサブクラスを、コンストラクタに渡された場合は空ですが、私はちょうど使用BeanUtils
することGCLIB
それ以外の場合は、コンストラクタサブクラスは、インスタンスを直接強化、サブクラスをインスタンス化。そして、メソッドのインターセプタを設定し、その呼び出しはあなたが容器の検索に行くことができ迎撃に入ると、作成されていない、直接のリターンがあります。
public Object instantiate(@Nullable Constructor<?> ctor, Object... args) {
Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
Object instance;
if (ctor == null) {
instance = BeanUtils.instantiateClass(subclass);
}
else {
try {
Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
instance = enhancedSubclassConstructor.newInstance(args);
}
catch (Exception ex) {
throw new BeanInstantiationException(this.beanDefinition.getBeanClass(),
"Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + "]", ex);
}
}
// SPR-10785: set callbacks directly on the instance instead of in the
// enhanced class (via the Enhancer) in order to avoid memory leaks.
Factory factory = (Factory) instance;
factory.setCallbacks(new Callback[] {NoOp.INSTANCE,
new LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),
new ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});
return instance;
}
ノートの戦闘LOOKUP
時には、あなたはとても実装クラスは、このような、依存していることを、実際には、実装クラスに依存して、インスタンス化のBeanへの書き込みノートに同じファイルを書きたくないことがあります。
しかし、我々はデカップリングする方法を考えますが、このことができクラスが依存するだろうspring
などと、あなたは他のフレームワークと独立して与えたい場合は、それはそうと推定されること、そしてまだ彼の方法を考える必要がないことxml
、またはカスタムポストプロセッサ。
これは、その後、問題を切り離す時間の実装:インターセプタは入って来、あなたが最後に呼び出すことで見ることができますあなたが望むタイプを渡して、これは:最後の内部には、中に封入し、戻り、その後、あなたはあなたを削除することができますオブジェクトは、もちろん、まだそこに呼んでいるべき取得します。我々は、単一の例のコンテナことがわかります。
LookupOverrideMethodInterceptor
owner.getBean
UserDao
NamedBeanHolder
getBeanInstance
getBean
注意点
同じタイプの2つの例は存在しない、または他の名前を指定するか、または例外を報告しない限り、彼は知っている、あなたが望むものではありませんありません。
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.ww.pojo.UserDao' available: expected single matching bean but found 2: testBean,userDao
あなたは、この名前を追加することができます。
または、このように:
さて、今日ここに、私たちは自分自身の学習、限られた容量を理解し、偉大な神は見スプレーしないで、言い訳してください、助けの調査に希望と理解しています。