https://jinnianshilongnian.iteye.com/blog/1487235
1、予選
[AOPの概念を参照してくださいhttp://www.iteye.com/topic/1122401 ]と[ http://jinnianshilongnian.iteye.com/blog/1418596 ]
トランザクション管理の春には、[参照してくださいhttp://jinnianshilongnian.iteye.com/blog/1441271 ]
使用AOPプロキシコールの実行処理の後、図に記載の方法。
ターゲットメソッドを終了するときには、私たちの最初の呼び出しではなく、対象物のAOPプロキシオブジェクトにある場合、トランザクションは最初のセクション、強化されたトランザクションTransactionInterceptorサラウンド機能拡張を介して内部総務課、それはターゲットメソッドの前に開いているトランザクションの中に、ある実行され、/ロールバックトランザクションをコミット。
2、テストする準備ができてコード
- パブリックインターフェイス隷属{
- ます。public void();
- 公共ボイドB();
- }
- @サービス()
- パブリッククラスAServiceImpl1は{AServiceを実装します
- @Transactional(伝播= Propagation.REQUIRED)
- 公共ボイドA(){
- this.b();
- }
- @Transactional(伝播= Propagation.REQUIRES_NEW)
- 公共ボイドB(){
- }
- }
3.問題
なお、図に示されている拡張の実施形態を、切断しないであろう対象物の内部に自分自身を呼び出します。
ここでは、これはターゲットオブジェクトにあるので、執行部を強化しないこと、総務課bが実行されません)(this.bを呼び出し、その取引方法は、B定義された「@Transactional(伝播は= Propagation.REQUIRES_NEW)」ではありません実施形態は、すなわち、結果がBであり、トランザクションの定義は、以下のログから見ることができる同じ方法です。
org.springframework.transaction.annotation.AnnotationTransactionAttributeSourceは、トランザクションメソッドを追加する「」属性を持つ:PROPAGATION_REQUIRED、ISOLATION_DEFAULT。「」
シングルトン豆のorg.springframework.beans.factory.support.DefaultListableBeanFactory戻るキャッシュされたインスタンスのtxManager "
名前[com.sishuok.service.impl.AServiceImpl1.a]で新しいトランザクションの作成org.springframework.orm.hibernate4.HibernateTransactionManager:PROPAGATION_REQUIRED、ISOLATION_DEFAULTを。'' -----创建方法事务
org.springframework.orm.hibernate4.HibernateTransactionManagerは、Hibernateのトランザクションのための新しいセッションを......開設---打开セッション
......
org.springframework.transaction.support.TransactionSynchronizationManager初期化トランザクションの同期
org.springframework.transaction.interceptor.TransactionInterceptorのトランザクションを取得[com.sishuok.service.impl.AServiceImpl1.a]
org.springframework.transaction.interceptor.TransactionInterceptor [com.sishuok.service.impl.AServiceImpl1.a] ----完成方法のためのトランザクションを完了事务
beforeCommit同期トリガorg.springframework.orm.hibernate4.HibernateTransactionManager
beforeCompletion同期トリガorg.springframework.orm.hibernate4.HibernateTransactionManager
org.springframework.orm.hibernate4.HibernateTransactionManager開始トランザクションがコミット
org.springframework.orm.hibernate4.HibernateTransactionManagerは、メソッドの総務を提出...... ---セッションにHibernateのトランザクションのコミット
若しくは
org.springframework.orm.hibernate4.HibernateTransactionManagerローリングバックメソッドがある場合、例外はトランザクションをロールバックします...... ---セッションでトランザクションを休止します
afterCommit同期トリガorg.springframework.orm.hibernate4.HibernateTransactionManager
afterCompletion同期トリガorg.springframework.orm.hibernate4.HibernateTransactionManager
org.springframework.transaction.support.TransactionSynchronizationManagerクリアトランザクションの同期
......
トランザクションの後...... HibernateのSessionを閉じるorg.springframework.orm.hibernate4.HibernateTransactionManager - 关闭セッション
私たちは、スライス取引方法取引の強化、B方式の無強化を見ることができます。
3、ソリューション
次のように方法bは、トランザクションを高めることができる方法の呼び出しセクションBのAOPプロキシを通過するトランザクション、限り、方法ここと呼ばれています。
- 公共ボイドA(){
- aopProxy.b();トランザクション補強セクションのトランザクションを実行するためにAOPプロキシオブジェクトbが呼び出される//方法
- }
豆は、プロキシオブジェクトのAOPは、次の3つの方法を使用できるかどうかを決定します。
AopUtils.isAopProxy(豆):プロキシオブジェクトかどうか;
AopUtils.isCglibProxy(豆):プロキシオブジェクトCGLIBの方法かどうか、
AopUtils.isJdkDynamicProxy(豆):プロキシオブジェクトJDKダイナミックプロキシアプローチかどうか;
3.1、ThreadLocalの量Aopによって公開されたプロキシオブジェクト
1 、オープン露光AOPのThreadLocalのにエージェントサポート(からspring3以下の構成サポート開始)
- <量Aop:AspectJの-自動プロキシ公開プロキシ= "真" /> <! - スタイル注釈のサポート - >
- <量Aop:設定は公開プロキシ= "真"> <! - XMLスタイルのサポート - >
2 、私たちのビジネスの実装クラスを変更します
this.b(); -----------変更--------->((AService)AopContext.currentProxy())B();
3 、ログとして、テストケースを実行します
シングルトン豆のorg.springframework.beans.factory.support.DefaultListableBeanFactory戻るキャッシュされたインスタンスのtxManager "
名前[com.sishuok.service.impl.AServiceImpl2.a]で新しいトランザクションの作成org.springframework.orm.hibernate4.HibernateTransactionManager:PROPAGATION_REQUIRED、ISOLATION_DEFAULTを。'' -----创建方法事务
打开セッション - org.springframework.orm.hibernate4.HibernateTransactionManagerは、Hibernateのトランザクションのために......新しいセッションを開設しました
HibernateのSessionのJDBC接続の準備org.springframework.orm.hibernate4.HibernateTransactionManager ......
JDBCトランザクションとしてHibernateのトランザクションを公開org.springframework.orm.hibernate4.HibernateTransactionManager ......
......
org.springframework.transaction.support.TransactionSynchronizationManager初期化トランザクションの同期
org.springframework.transaction.interceptor.TransactionInterceptorのトランザクションを取得[com.sishuok.service.impl.AServiceImpl2.a]
属性でトランザクションメソッド「b」を追加org.springframework.transaction.annotation.AnnotationTransactionAttributeSource:PROPAGATION_REQUIRES_NEW、ISOLATION_DEFAULT。「」
......
org.springframework.orm.hibernate4.HibernateTransactionManagerは[com.sishuok.service.impl.AServiceImpl2.b] ----- B法トランザクションを作成(およびメソッド総務を一時停止)するための名前で新しいトランザクションを作成し、現在のトランザクションを一時停止します
......
org.springframework.orm.hibernate4.HibernateTransactionManagerは--- Hibernateのトランザクションのための新しいセッションを開いた打开セッションB
......
org.springframework.transaction.support.TransactionSynchronizationManager初期化トランザクションの同期
org.springframework.transaction.interceptor.TransactionInterceptorのトランザクションを取得[com.sishuok.service.impl.AServiceImpl2.b]
org.springframework.transaction.interceptor.TransactionInterceptor [com.sishuok.service.impl.AServiceImpl2.b] ----完成Bの方法のためのトランザクションを完了事务
beforeCommit同期トリガorg.springframework.orm.hibernate4.HibernateTransactionManager
beforeCompletion同期トリガorg.springframework.orm.hibernate4.HibernateTransactionManager
org.springframework.orm.hibernate4.HibernateTransactionManager開始トランザクションがコミット
org.springframework.orm.hibernate4.HibernateTransactionManagerは、トランザクションBを提出する...... ---セッションのメソッドをHibernateのトランザクションのコミット
afterCommit同期トリガorg.springframework.orm.hibernate4.HibernateTransactionManager
afterCompletion同期トリガorg.springframework.orm.hibernate4.HibernateTransactionManager
org.springframework.transaction.support.TransactionSynchronizationManagerクリアトランザクションの同期
......
トランザクションの後...... HibernateのSessionを閉じるorg.springframework.orm.hibernate4.HibernateTransactionManager - 关闭Bセッション
B -----このメソッドのトランザクションが完了しました
org.springframework.orm.hibernate4.HibernateTransactionManager再開は---内側のトランザクションの完了後にトランザクションを中断し恢复方法を事务
......
org.springframework.transaction.support.TransactionSynchronizationManager初期化トランザクションの同期
org.springframework.transaction.interceptor.TransactionInterceptor [com.sishuok.service.impl.AServiceImpl2.a] ----完成方法のためのトランザクションを完了事务
beforeCommit同期トリガorg.springframework.orm.hibernate4.HibernateTransactionManager
beforeCompletion同期トリガorg.springframework.orm.hibernate4.HibernateTransactionManager
org.springframework.orm.hibernate4.HibernateTransactionManager開始トランザクションがコミット
org.springframework.orm.hibernate4.HibernateTransactionManagerは、メソッドの総務を提出...... ---セッションにHibernateのトランザクションのコミット
afterCommit同期トリガorg.springframework.orm.hibernate4.HibernateTransactionManager
afterCompletion同期トリガorg.springframework.orm.hibernate4.HibernateTransactionManager
org.springframework.transaction.support.TransactionSynchronizationManagerクリアトランザクションの同期
......
トランザクションの後...... HibernateのSessionを閉じるorg.springframework.orm.hibernate4.HibernateTransactionManager - 关闭セッション
ここでは、B見ることができる方法の業務機能を。
ターゲットオブジェクト上の方法は、自分自身を呼び出す内部メソッドを解決し、最も簡単な解決策トランザクションを実装することです。
4 、実装原理解析
4.1、現在のThreadLocalにAopContext.serCurrentProxy(プロキシ)プロキシオブジェクトによって公開されたプロキシオブジェクトを入力した後、ThreadLocalのとoldProxyにバインドされた最後のプロキシオブジェクトを保存します。
4.2、我々は)(現在のプロキシオブジェクトAopContext.currentProxyを取得することができます。
AopContext.serCurrentProxy(oldProxy)最後のプロキシオブジェクトに再ThreadLocalのプロキシ・バインディング・オブジェクトへのプロキシオブジェクトを出る前に4.3。
ThreadLocalのへの暴露に関連する(セッションおよび接続)内政がSessionHolderとConnectionHolderによって実装されているため、一部の人々はこの方法を好きではない、露出ThreadLocalのパフォーマンスの問題で言って、実際には、この必要性は、考慮されません。
ただし、このシナリオでは、ほんの数例が発生したので、次のように我々はこのような方法でも達成することができない、本当に自分自身を呼び出します。
3.2、初期化方法によって対象物にプロキシオブジェクトを注入します
- @サービス
- パブリッククラス{AServiceImpl3の隷属を実装します
- //①注入し、コンテキスト@Autowired
- プライベートApplicationContextのコンテキスト。
- プライベートAService proxySelf; //②は、プロキシオブジェクトではなく、ターゲットオブジェクトを表し
- @PostConstruct //③初期化子
- プライベートボイドsetSelf(){
- //(proxtSelfで=これが間違っている場合、これは観客である)プロキシオブジェクトからコンテキストを取得します。
- 毎回新しいgetBeanがビーンを返すので、//このメソッドは、プロトタイプビーンには適していません
- proxySelf = context.getBean(AService.class)。
- }
- @Transactional(伝播= Propagation.REQUIRED)
- 公共ボイドA(){
- proxySelf.b();あなたが取引のセクションを実行できるように//④プロキシオブジェクトのメソッドを呼び出します
- }
- @Transactional(伝播= Propagation.REQUIRES_NEW)
- 公共ボイドB(){
- }
- }
ログ分析はここではない、と3.1は似ています。この方法では、クラスが自己呼び出しを達成するために必要なすべての実装コードを繰り返す必要があり、非常に柔軟ではありません。
対象物に3.3、注射によるBeanPostProcessorプロキシオブジェクト
このような溶液は、参照することができhttp://fyting.iteye.com/blog/109236を。
BeanPostProcessorの導入と使用が私の次のポスト解析のためにお待ちください。
I.定義BeanPostProcessorの インタフェースの識別子を使用する必要があります
- パブリックインターフェースBeanSelfAware {
- 空setSelf(proxyBeanオブジェクト)。
- }
あなたが私たちのアイデンティティーBeanのプロキシオブジェクトを注入setSelfと呼ばれるインタフェースの実現である見つけた場合はそれが私たちのカスタムBeanPostProcessor定義(InjectBeanSelfProcessor)です。
二、豆が実現
- @サービス
- パブリッククラスAServiceImpl4はAService、BeanSelfAware {//インタフェース定義は省略する実装します
- proxySelfプライベート隷属。
- 公共ボイドsetSelf(proxyBeanオブジェクト){// InjectBeanSelfProcessorによって移植自体(ターゲットオブジェクト)AOPプロキシオブジェクト
- this.proxySelf =(AService)proxyBean。
- }
- @Transactional(伝播= Propagation.REQUIRED)
- 公共ボイドA(){
- proxySelf.b();あなたが取引のセクションを実行できるように//プロキシオブジェクトのメソッドを呼び出します
- }
- @Transactional(伝播= Propagation.REQUIRES_NEW)
- 公共ボイドB(){
- }
- }
インターフェイスプロキシオブジェクトsetSelf注射の識別子を実装し、トランザクション定義方法Bの「proxySelf.b()」本実施例によってBeanSelfAware。
三、InjectBeanSelfProcessorを達成
- @成分
- パブリッククラスInjectBeanSelfProcessorは{BeanPostProcessorを実装します
- パブリックオブジェクトpostProcessBeforeInitialization(オブジェクト・ビーン、文字列のbeanName)がBeansExceptionを{スロー
- Beanを返します。
- }
- パブリックオブジェクトpostProcessAfterInitialization(オブジェクト・ビーン、文字列のbeanName)がBeansExceptionを{スロー
- 豆が実装している場合(BeanSelfAware instanceofの豆){// BeanSelfAware識別インターフェイスプロキシオブジェクトは、注入される場合
- ((BeanSelfAware)豆).setSelf(豆); //でもプロトタイプビーンもこの方法で使用することができます
- }
- Beanを返します。
- }
- }
postProcessAfterInitializationターゲットオブジェクトは、ターゲットオブジェクトの内部コール自体を完了するために、それによって、ターゲットオブジェクトにsetSelf(豆)プロキシオブジェクト(豆)によって識別係るBeanSelfAwareインターフェイスを実現されているかどうか。
BeanPostProcessor実行フローなどについての私のこの記事を参照してください、または実装を下に継続することはできません。
四、InjectBeanSelfProcessor 問題
(1 、シーン:プロキシオブジェクトInjectBeanSelfProcessorと循環依存関係を注入設定することはできません前者の問題により、現場で発生したプロキシオブジェクトsetSelf循環依存関係は避けるべきであるが、実際の仕事、必然的に誰かがいない、結局、この注入を使用します。必須。
(2、用例
(2.1 、定義BeanPostProcessorの インタフェースの識別子が使用する必要が
そして3.1同じことがここでは繰り返しません。
(2.2 、豆が実現
- @サービス
- パブリッククラスAServiceImplはAService、BeanSelfAware {//インタフェースの定義は省略するAserviceを実装します
- @Autowired
- プライベートBService bService; //①注射BServiceによって@Autowired方法
- プライベートAService自己; //②自分のAOPプロキシオブジェクトに
- 公共ボイドsetSelf(proxyBeanオブジェクト){
- =(AService)proxyBean this.self; //③InjectBeanSelfProcessorによって注射自体(ターゲットオブジェクト)AOPプロキシオブジェクト
- System.out.println( "AService ==" + AopUtils.isAopProxy(this.self)); //出力正体AOPプロキシオブジェクト成功した注射の場合
- }
- @Transactional(伝播= Propagation.REQUIRED)
- 公共ボイドA(){
- self.b();
- }
- @Transactional(伝播= Propagation.REQUIRES_NEW)
- 公共ボイドB(){
- }
- }
- @サービス
- パブリッククラスBServiceImplはBService、BeanSelfAware {//インタフェースの定義は省略するAserviceを実装します
- @Autowired
- プライベートAService aService; //①注入AServiceによって@Autowired方法
- プライベートBService自己; //②自分のAOPプロキシオブジェクトに
- プロキシオブジェクトAOPの自身(対象物)を注入することによって公共ボイドsetSelf(proxyBeanオブジェクト){//③InjectBeanSelfProcessor
- this.self =(BService)proxyBean。
- System.out.println( "BService =" + AopUtils.isAopProxy(this.self)); //出力正体AOPプロキシオブジェクト成功した注射の場合
- }
- @Transactional(伝播= Propagation.REQUIRED)
- 公共ボイドA(){
- self.b();
- }
- @Transactional(伝播= Propagation.REQUIRES_NEW)
- 公共ボイドB(){
- }
- }
ここではA依存B、B依存Aは、唯一の問題は、プロキシオブジェクトは、円形の依存関係の失敗を表示します注入理由を探るために、(実際の作業は、循環依存を避けるべき)設計の問題に循環依存関係を議論するために、ここで、依存関係のサイクルではなくなります。
循環依存関係は、私のブログ[参照してくださいhttp://jinnianshilongnian.iteye.com/blog/1415278 ]。
依存の初期化と破壊の順序は、私のブログ[参照してくださいhttp://jinnianshilongnian.iteye.com/blog/1415461 ]。
(2.3 、InjectBeanSelfProcessorを達成
そして、同じ前に3.3は、ここでは繰り返しません。
(2.4 、テストケース
- @RunWith(値= SpringJUnit4ClassRunner.class)
- @ContextConfiguration(値= { "クラスパス:春-config.xmlの"})
- パブリッククラスSelfInjectTest {
- @Autowired
- 年季奉公隷属;
- @Autowired
- BService bService;
- @テスト
- 公共ボイド試験(){
- }
- }
出力テストを実行します。
BService =真
== falseの隷属
BService正常プロキシオブジェクトを介して注入InjectBeanSelfProcessorが、そのAServiceと(実際に対象物に注入)失敗し、デバッグ情報が得られる次のように
(2.5 、なぜ、どのようにこれは、依存関係のサイクルで起こるだろうされていますか?
私の次のポスト解析用にチューニング滞在。
3.4、InjectBeanSelfProcessorソリューションの改良版
- @成分
- パブリッククラスInjectBeanSelfProcessor2はBeanPostProcessor、ApplicationContextAwareを{実装します
- プライベートApplicationContextのコンテキスト。
- //①注入のApplicationContext
- 公共ボイドsetApplicationContext(ApplicationContextのApplicationContextの)はBeansExceptionを{スロー
- this.context =のApplicationContext。
- }
- パブリックオブジェクトpostProcessAfterInitialization(オブジェクト・ビーン、文字列のbeanName)がBeansExceptionを{スロー
- もし(BeanSelfAwareのinstanceof!(豆)){//②Beanの識別をスキップするためのインタフェースを実装していない場合はBeanSelfAware
- Beanを返します。
- }
- (AopUtils.isAopProxy(豆)){//③現在のオブジェクトがプロキシオブジェクトAOPである場合、直接注射する場合
- ((BeanSelfAware)豆).setSelf(豆)。
- }他{
- //④現在のオブジェクトではなくAOPプロキシ、context.getBean(のbeanName)によって取得されたプロキシオブジェクトと注入される場合
- //これはプロトタイプビーンプロキシオブジェクト注入を解決するためには適していません
- ((BeanSelfAware)の妻).setSelf(context.getBean(のbeanName));
- }
- Beanを返します。
- }
- パブリックオブジェクトpostProcessBeforeInitialization(オブジェクト・ビーン、文字列のbeanName)がBeansExceptionを{スロー
- Beanを返します。
- }
- }
5、要約
その上を通じて:
[3.1 ThreadLocalのAOPのプロキシ・オブジェクトによって露出] AOPプロキシ・アクセスの問題(すなわち、ターゲット・オブジェクト自体を呼び出す問題を解決することが可能である)のすべてのシーン(シングルトンBeanまたはプロトタイプビーンかどうか)を解決するため、
[3.2ターゲット・オブジェクトでプロキシオブジェクトを介して注入イニシャライザと[3.4] InjectBeanSelfProcessorを解決するために、溶液のバージョンを改善】プロキシオブジェクトAOP噴射問題の正常(非円形の依存性)だけでなく、[3.3]上述の解決対象物体の循環依存は、(シングルトン間の循環依存性であるべきである)注射AOPプロキシオブジェクトの問題に起因することはできないが、溶液が循環依存の問題を解決するためには適していない自分自身を呼び出すことプロトタイプビーンを含み、
[ターゲットオブジェクトプロキシオブジェクトによって注入3.3 BeanPostProcessor:のみ、通常の(非円形の依存関係)を解くビーン噴射AOPプロキシのは、自分自身を呼び出す円形の依存性注入問題AOPプロキシオブジェクトは、ターゲットオブジェクトの問題を解決することはできません解決することができません。
完璧なソリューション、唯一の最適な解決策はありません。
付属のテスト、ジャーパッケージを参照してくださいhttp://www.iteye.com/topic/1120924それを用いました