すごい!Spring5 AOPはデフォルトでCGLIBを使用しますか?現象からソースコードまでの詳細な分析

Spring5 AOPはデフォルトでCglibを使用しますか?この声明を初めて聞いたのはWeChatグループでした。

グループチャット

本物か偽物か?ドキュメントを見る

この声明を最初に見たとき、私は懐疑的でした。

Spring5より前のバージョンのAOPがデフォルトでJDK動的プロキシを使用していることは誰もが知っていますが、Spring5のバージョンが変更されているというのは本当ですか?そこで、Spring Framework 5.xドキュメントを開いて、もう一度確認しました。

ドキュメントアドレス:https://docs.spring.io/spring/docs/5.2.0.RELEASE/spring-framework-reference/core.html#aop

Spring Framework5.xのドキュメント

単に翻訳してください。Spring AOPは、デフォルトでJDK動的プロキシを使用します。オブジェクトがインターフェイスを実装していない場合は、CGLIBプロキシを使用します。もちろん、CGLIBプロキシの使用を強制することもできます。

何?間違った文書?

公式文書をグループに送った後、このクラスメートから次のような返信がありました。

間違った文書?

SpringBoot2.xのコード例

文書が間違っていたことを証明するために、学生はデモも書きました。それでは、デモプログラムを再現しましょう。

動作環境:SpringBoot 2.2.0.RELEASEバージョン、組み込みのSpringFrameworkバージョンは5.2.0.RELEASEバージョンです。同時に、spring-boot-starter-aop依存関係を追加して、SpringAOPを自動的にアセンブルします。

public interface UserService {
    void work();
}

@Service
public class UserServiceImpl implements UserService {

    @Override
    public void work() {
        System.out.println("开始干活...coding...");
    }
}
@Component
@Aspect
public class UserServiceAspect {
    @Before("execution(* com.me.aop.UserService.work(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("UserServiceAspect.....()");
    }
}

Cglibプロキシはデフォルトで使用されますか?

UserServiceImplUserServiceインターフェースである実装、及び方法は、事前拡張傍受するために使用されます。UserServiceAspectUserService#work

実行結果から判断すると、ここではJDK動的プロキシの代わりにCGLIBプロキシが実際に使用されています。

ドキュメントは本当に間違っていますか?

@EnableAspectJAutoProxyソースコード注釈

Spring Frameworkでは、@EnableAspectJAutoProxy注釈を使用してSpringAOP関連の機能を有効にします。

Spring Framework5.2.0.RELEASEバージョンの@EnableAspectJAutoProxy注釈のソースコードは次のとおりです。

@EnableAspectJAutoProxyソースコード

ソースコードのコメントから、次のことがわかります。SpringFramework 5.2.0.RELEASEバージョンでproxyTargetClassは、デフォルト値がfalseデフォルトのままであるか、JDK動的プロキシがデフォルトで使用されます。

ドキュメントとソースコードのコメントは間違っていますか?

@EnableAspectJAutoProxyのproxyTargetClassが無効ですか?

次に、@EnableAspectJAutoProxyJDK動的プロキシの使用を強制しようとしました。

動作環境:SpringBoot 2.2.0.RELEASEバージョン、組み込みのSpringFrameworkバージョンは5.2.0.RELEASEバージョンです。

proxyTargetClassの設定が無効ですか?

実行中に、CGLIBプロキシがまだ使用されていることがわかりました。ある設定無効は?@EnableAspectJAutoProxyproxyTargetClass

Spring Framework 5.x

アイデアを整理する

  1. Spring5はAOPを開始し、デフォルトでCGLIBを使用すると言う人もいます。

  2. Spring Framework 5.xのドキュメントと @EnableAspectJAutoProxyソースコードのコメントはすべて、デフォルトではJDK動的プロキシを使用することであると述べています

  3. プログラムの操作結果は、インターフェースが継承されproxyTargetClassfalse設定さている場合でも、プログラムはCGLIBプロキシを使用していることを示しています。

ちょっと待ってください、何か足りないのですか?

サンプルプログラムはSpringBootを使用して実行されます。SpringBootを使用せず、SpringFrameworkのみを使用する場合はどうなりますか?

動作環境:Spring Framework5.2.0.RELEASEバージョン。UserServiceImplクラスとUserServiceAspectクラスは上記と同じなので、ここでは繰り返しません。

Spring Framework 5.x Spring Framework 5.xLingageCGLIB

実行結果は次のことを示しています。SpringFramework5.xバージョンでは、クラスがインターフェイスを実装している場合、AOPはデフォルトでJDK動的プロキシを使用します。

アイデアを再編成する

  1. Spring5 AOPは引き続きデフォルトでJDK動的プロキシを使用しており、公式ドキュメントとソースコードのコメントは正しいです。

  2. SpringBoot 2.xバージョンでは、AOPはデフォルトでcglibを使用し、proxyTargetClass変更できません。

  3. SpringBoot 2.xはいくつかの変更を加えましたか?

SpringBoot2.xに再度アクセスします

上記の分析の結果、Spring Boot2.xバージョンがSpringAOPの関連する構成を変更した可能性が非常に高いです。次に、ソースコード分析の波を見て、内部で何が行われたかを確認しましょう。

ソースコード分析

ソースコード分析、適切なエントリを見つけることは非常に重要です。今回の入り口はどこですか?

@SpringBootApplication@EnableAutoConfiguration多数の自動組立実現するために使用される複合注釈です。

EnableAutoConfigurationこれは、注釈にマークされている結合注釈でもあり@Importます。@Import詳細な使用注釈、著者の以前の記事を参照してください。https://mp.weixin.qq.com/s/7arh4sVH1mlHE0GVVbZ84Q

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

AutoConfigurationImportSelectorDeferredImportSelectorインターフェイスが実装されています。

Spring Framework 4.xバージョンでは、これは空のインターフェイスであり、ImportSelectorインターフェイスを継承するだけです。5.xバージョンでは、DeferredImportSelectorインターフェイスが拡張され、getImportGroupメソッドが追加されました。

AutoConfigurationImportSelector#getImportGroup

AutoConfigurationGroupクラスはこのメソッドで返されます。これはAutoConfigurationImportSelectorDeferredImportSelector.Groupインターフェイスを実装する内部クラスです。

SpringBoot 2.xバージョンでは、AutoConfigurationImportSelector.AutoConfigurationGroup#process自動構成クラスはメソッドを介してインポートさます。

構成クラスのインポート

ブレークポイントのデバッグを通じて、AOPに関連する自動構成がによって構成されていることがわかりorg.springframework.boot.autoconfigure.aop.AopAutoConfigurationます。

AopAutoConfigurationソースコード

真実が明らかにされる

これを見て、真実が明らかにされたと言えます。SpringBoot 2.xバージョンでAopAutoConfigurationAOPはにまで自動的にアセンブルれます。

デフォルトでは、spring.aop.proxy-target-classそのような構成アイテムは絶対にありません現時点では、SpringBoot2.xではCglibがデフォルトで使用されます。

SpringBoot2.xでAOP実装を変更する方法

ソースコードを通じて、SpringBoot 2.xでAOPの実装を変更する必要がある場合は、spring.aop.proxy-target-classこの構成アイテムを介して変更する必要があることもわかります。

#在application.properties文件中通过spring.aop.proxy-target-class来配置
spring.aop.proxy-target-class=false

spring-configuration-metadata.json

spring-configuration-metadata.jsonファイルの役割についても説明します。application.propertiesまたはapplication.ymlファイルを使用する場合、IDEAはこれらのファイル情報を読み取ることでコードヒントを提供し、SpringBootフレームワーク自体はこの構成ファイルを読み取りません。

SringBoot1.5.xはどうですか

SringBoot 1.5.x

ご覧のとおり、SpringBoot 1.5.xでは、JDK動的プロキシがデフォルトで引き続き使用されます。

SpringBoot2.xがデフォルトでCglibを使用する理由

SpringBoot 2.xがデフォルトでCglibを使用してAOPを実装するのはなぜですか?これを行うことの利点は何ですか?著者はインターネットからいくつかの情報を見つけました。最初に問題を見てみましょう。

Spring Bootの問題#5423

@EnableTransactionManagement(proxyTargetClass = true)#5423を使用します

https://github.com/spring-projects/spring-boot/issues/5423

この号では、次のような問題が発生しました。

image.png

翻訳:人々がインターフェースを使用しないときに迷惑なプロキシの問題を防ぐために、@ EnableTransactionManagement(proxyTargetClass = true)を使用する必要があります。

この「インターフェースを使用しないときの厄介なプロキシの問題」とは何ですか?ちょっと考えてみてください。

迷惑な代理店の問題

現時点で使用する必要のあるUserServiceImplsumUserServiceクラスがあるとしますSpringでは、通常、次のようなコードを記述するために使用されます。UserContollerUserService

@Autowired
UserService userService;

この場合、JDKダイナミックプロキシとCGLIBのどちらを使用していても問題ありません。

しかし、コードが次のような場合はどうなりますか?

@Autowired
UserServiceImpl userService;

現時点で、JDK動的プロキシを使用している場合、起動時にエラーが報告されます。

起動エラー

JDK動的プロキシはインターフェイスベースであるため、プロキシによって生成されたオブジェクトは、インターフェイス変数にのみ割り当てることができます。

そして、CGLIBにはこの問題はありません。CGLIBはサブクラスを生成することによって実装されるため、プロキシオブジェクトがインターフェイスに割り当てられているか実装クラスに割り当てられているかに関係なく、どちらもプロキシオブジェクトの親クラスです。

SpringBootは正確にこの考慮事項から外れているため、バージョン2.xでは、AOPのデフォルトの実装がCGLIBに変更されました。

より詳細な情報については、読者は自分で上記の問題を参照することができます。

総括する

  1. Spring 5.xでも、AOPはデフォルトでJDK動的プロキシを使用します。

  2. SpringBoot 2.x以降、JDK動的プロキシの使用によって発生する可能性のある型変換例外を解決するために、デフォルトでCGLIBが使用されます。

  3. SpringBoot 2.xでは、デフォルトでJDK動的プロキシを使用する必要がある場合、構成アイテムを使用してspring.aop.proxy-target-class=false変更できproxyTargetClass構成は無効です。

参考文献

問題:デフォルトのCGLibプロキシ設定のデフォルトは、コアフレームワークアノテーション(@ EnableTransactionManagement、@ EnableAspectJAutoProxy)を使用してオーバーライドできません#12194

https://github.com/spring-projects/spring-boot/issues/12194

この問題proxyTargetClass@EnableAspectJAutoProxy議論の失敗を設定する問題についても話します:、、@EnableCaching および @EnableTransactionManagement興味のある読者は自分で問題を調べることができます。

オリジナル:https//javazhiyin.blog.csdn.net/article/details/103296297

史上最強のTomcat8パフォーマンス最適化

なぜアリババは90秒で100億に抵抗できるのですか?-サーバー側の高同時分散アーキテクチャの進化

B2Beコマースプラットフォーム--ChinaPayUnionPay電子決済機能

Zookeeperの分散ロックを学び、インタビュアーに感心してあなたを見てもらいましょう

SpringCloudeコマーススパイクマイクロサービス-Redisson分散ロックソリューション

もっと良い記事をチェックして、公式アカウントを入力してください-私にお願いします-過去に素晴らしい

深くソウルフルなパブリックアカウント0.0

 

おすすめ

転載: blog.csdn.net/a1036645146/article/details/112172174
おすすめ