背景:
Googleのオープンソースのローカルデータベースのクエリキャッシュソリューションを使用する際には、多くの場合、非効率的なクエリ、キャッシュに優れたデータからデータベースクエリになり、その後、さらにプロセス全体のパッケージに集約、データ・キャッシュを取得する方法を設計するために取得後、有効期限を設計し、 CacheSericeにし、サービスからデータを取得し、サービスにコントローラ層を呼び出します。
問題:
キャッシュデータが初期化されているロードされているサービスの豆、(データベースクエリ・サービスのすなわち使用は、データを取得するために、キャッシュを詰め)とき、および初期化プロセスは、私が入れている:のCacheServiceの必要性は、もともと設計し、初期化しますクラスのコンストラクタへのCacheService。結果は、新聞、NULLポインタで公開されています。
@Service( "試験")
パブリッククラステスト実装IAppnameCache {
@Autowired
IAppnameService iAppnameService。
パブリックテスト(){
iAppnameService.queryAppname()。//抛出空指针
}
@Override
公衆リスト<AppnameViewModel> GET(文字列APP){
iAppnameService.queryAppname()を返します。
}
}
問題を見つけます。
クエリログ後とするとき、コンストラクタの実行ヌルポインタのCacheServiceの問題が発生しました。そして、問題は、Googleのオープンソースライブラリを導入することも排除のプロセスが存在してもしなくてもよい、すぐにテストクラス採用のGoogleのオープンソースライブラリせずに、このようなアプローチはまた、NULLポインタを受けている、問題は、ライブラリの問題ではありません発見しました。
質問を考えます:
Googleのオープンソース・ライブラリーの導入とは関係がないので、ヌルポインタの問題をもたらす、他のビーンに依存している構造のCacheServiceを、(コンストラクタを使用して)場合がまだ構築されていないことを示しています。この問題のためのSpring Beanの設定プロセスのさらなる研究。
SpringのBeanのロード処理:
次のようにメインの豆の生成プロセスは、次のとおりです。
1、AbstractBeanFactory.getBean(文字列) 2、AbstractBeanFactory.doGetBean(文字列、クラス<T>、オブジェクト[]、ブール) 3、DefaultSingletonBeanRegistry.getSingleton(文字列) 4、AbstractAutowireCapableBeanFactory.createBean(文字列、RootBeanDefinition、オブジェクト[]) 5 、AbstractAutowireCapableBeanFactory.doCreateBean(文字列、RootBeanDefinition、オブジェクト[]) 6、AbstractAutowireCapableBeanFactory.createBeanInstance(文字列、RootBeanDefinition、オブジェクト[]) 7、AbstractAutowireCapableBeanFactory.instantiateBean(文字列、RootBeanDefinition) 8、SimpleInstantiationStrategy.instantiate(RootBeanDefinition、文字列たBeanFactory) 9 、AbstractAutowireCapableBeanFactory.populateBean(文字列、RootBeanDefinition、BeanWrapper) 10 、AbstractAutowireCapableBeanFactory.initializeBean(文字列、オブジェクト、RootBeanDefinition) 11、AbstractAutowireCapableBeanFactory.invokeAwareMethods(文字列、オブジェクト) 12、AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(オブジェクト、文字列) 13、AbstractAutowireCapableBeanFactory.invokeInitMethods(文字列、オブジェクト、RootBeanDefinition) 14、AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(オブジェクト、文字列)
直接リターンがある場合(1)豆たBeanFactory時間を取得することによって、オブジェクトのインスタンスでは、コレクションが作成されているかどうかに対応した単一の実施形態の例を見つけるために行くが、これは第1の取得であり、いかなるGETはありません。
(2)次にAbastractBeanFactory BeanDefinitionを対応する名前でビーンオブジェクトオブジェクトが依存する場合か他の目的、その他の目的に依存し、かどうかBeanDefinition単一の実施形態に応じて決定することができるので、BeanDefinitionは、メタデータに対応するさまざまなクラスを表すオブジェクトを取得しますその信頼にミスターので、ここでは再帰呼び出しです。
ステップ7は、Beanを生成する準備をする前に、豆は、実際instantiateBean方法のAbstractAutowireCapableBeanFactoryに生成されます。
保護BeanWrapper instantiateBean(最終列のbeanName、最終RootBeanDefinitionのMBD){ 試み{ オブジェクトbeanInstance。 最終たBeanFactoryの親は、この=。 もし(System.getSecurityManager()!= NULL){ beanInstance = AccessController.doPrivilegedの(新たPrivilegedAction <オブジェクト>(){ @Override パブリックオブジェクトの実行(){ リターンgetInstantiationStrategy()インスタンス化(MBD、のbeanName、親); } } 、getAccessControlContext())。 } 他{ beanInstance = getInstantiationStrategy()インスタンス化(MBD、のbeanName、親)。 } BeanWrapper BW =新しいBeanWrapperImpl(beanInstance)。 initBeanWrapper(BW)。 体重返します。 } キャッチ(ThrowableのEX){ 新しいBeanCreationExceptionスロー( mbd.getResourceDescriptionを()、のbeanNameは、 "豆のインスタンス化に失敗しました"、EX); } }
------------------------------------------------ -------------------------------------------------- ---
@Override
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) { // Don't override the class with CGLIB if no overrides. if (bd.getMethodOverrides().isEmpty()) { Constructor<?> constructorToUse; synchronized (bd.constructorArgumentLock) { //这里一堆安全检查 } //默认使用构造函数利用反射实例化bean return BeanUtils.instantiateClass(constructorToUse); } else { // Must generate CGLIB subclass. return instantiateWithMethodInjection(bd, beanName, owner); } }
実際には、あなたは、Beanが直接生成されて見ることができますBeanUtils工具类通过反射获取类的实例。
反射したクラスのインスタンスを取得し、次のとおりです。
クラスCLS = Class.forNameの(<?> "cn.mldn.demo.Person"); // クラスオブジェクト取得した オブジェクトOBJ = cls.newInstance()//インスタンス化オブジェクトリフレクタ <?>コンストラクタ短所= cls.getConstructor( String.class、int.classを); //取得コンストラクタ メソッド立方メートル= cls.getDeclaredMethod( "のgetName" ); // ゲットする方法 フィールドnameField = cls.getDeclaredField( "名前" ); //は、 name属性を取得します
クラスがJVMにロードされ、同時に、このステップを初期化するために、まず最初に、変数を初期化するデフォルトコンストラクタを呼び出すために、次のようになります。
- クラスコンストラクタ<clinit>()メソッドは、すべてのクラス変数および文の(静的ブロック)の静的ステートメントブロックの合併、ソースファイル内のステートメントによって収集順コンパイラ割り当て動作コンパイラ自動的に収集クラスであります静的ステートメントブロックの前にステートメントのブロック内で定義された静的変数へのアクセスのみによって決定される順序で表示され、それが変数で定義された後、あなたは、静的ステートメントの前に高速で割り当てることができますが、アクセスすることはできません。
- クラスのコンストラクタのクラスコンストラクタ<clinit>()メソッド(インスタンスコンストラクタの<init>()メソッド)異なる、それが明示的に、仮想マシンを確保するために実施された親クラスの設定を呼び出すことはありません。そのサブクラス<clinit>()メソッド親クラスの前に<clinit>()メソッドが完了しました。したがって、仮想マシン内のクラスは、最初の<clinit>実行()メソッドは、java.lang.Objectのなければなりません。
- 親クラスで定義されている静的ステートメントを意味最初の<clinit>()メソッドが実行の親は、可変サブクラス割当てよりも優先としているように。
- クラスではなく、静的文、また操作変数代入を行う場合は、クラスまたはインタフェースの<Clinit>()メソッドは、必要ではないが、コンパイラは、クラス<clinit>()メソッドのために生成されなくてもよいです。(デフォルトが与えられたときにメモリ割り当てにかかわらず、初期化処理の)
- インターフェイスブロック静的ステートメントを実装インターフェイス<clinit>()メソッドは、親インタフェース<clinit>()メソッドを実行する必要がないことが、異なるインターフェイスとクラスで、使用することができません。インタフェースで定義された親の変数が使用された場合にのみ、親インタフェースが初期化されます。さらに、初期のインターフェイスの実装クラスが実行されなかった<clinit>()インターフェース方法。
- クラス<clinit>()メソッドが正しくマルチスレッド環境でロックされ、複数のスレッドがクラスを初期化する場合、同期、そして唯一のこのクラス<clinit>()メソッドの1回のスレッドの実行が存在することを確保するための仮想機会他のスレッドは<clinit>()メソッドが完了しているアクティブなスレッドの実行まで待つ必要がブロックされています。クラス<clinit>()メソッドは、操作があると長い時間を要する場合には、複数のプロセス障害をもたらし得ます。
CacheServiceクラス、コンストラクタが取得された反射時間が明示的にコンストラクタを呼び出しますので、のCacheServiceの動作は、デフォルトのコンストラクタが呼ばれるクラス割り当てではありません。他のBeanのコンストラクタで、この問題に戻り、豆春生成するには、実際に(依存Beanが注入されてはいない、である)法律ではありませんので、NULLポインタ例外がスローされます。
そこで質問があり、春には、自動検出とイエスは、機能を依存していると?
親愛なる読者は、あなたが解凍するためのニッチを喜ば、ゆっくり見てください。
私たちは、見た目を楽しみにして、あなたはコンテナ内の対象Beanを取得していない場合は、AbastractBeanFactory名前でBeanDefinitionのターゲットBeanに対応するでしょう、BeanDefinitionオブジェクトは、クラスに対応した様々なメタデータを表し、
//実行Beanは豆依存豆得るために、作成されていないここに記載 ; String []型DEPENDSON mbd.getDependsOnを=() (!= NULL DEPENDSON)IF { {(DEPENDSON DEP文字列)について IF(isDependent(のbeanName 、DEP)){ スロー新しい新しいBeanCreationException(mbd.getResourceDescription()、のbeanName、 "ON間の循環-関係依存'" +のbeanName + " 'および'" + DEP + "'"); } registerDependentBean(DEP、のbeanName)。 //インスタンス化依存ビーン getBean(DEP); } }
それは、取得した依存getDependsOn法Beanで見ることができ、このプロセスは、のCacheService setterプロパティ豆を介して注入され、その後、豆を得ました。まあ、噴射時間のプロパティから
IAppnameServiceは、Beanに完了している、またはなぜコンストラクタが例外はスローされますか?追加され、このプロセスが依存していることは、元の注射明らかは、依存オン(また、注釈をサポートしている)Bean構成に、
構成されていない場合、その後のCacheServiceプロパティは(getbean後に注入される)完全に。だから、コンストラクタの実装はもちろん、例外をスローで、それのCacheService!だから、Springの依存性チェックが実際に開いていないことを、
手動で設定ファイルを開く必要があり、春にやり方をチェック4つの依存性があります。依存関係のチェックは4つのモードがあります:シンプルに、オブジェクトは、すべて、どれも 、 mode属性の依存関係チェックBeanによって設定されていません。
もちろん、ローディング、またはJVMのロードプロセスに従うスプリング、ローディングプロセス。
JVMのメインロード処理
(続く)参考文献:
仮想マシンの1 JVM深い理解
2. https://blog.51cto.com/wenshengzhu/1950146
3. https://blog.csdn.net/h12kjgj/article/details/54312766
4。https://www.cnblogs.com/kjitboy/p/12076303.html [ スプリング組立方法ビーン