AOPの実現原理——スタティックエージェントとダイナミックエージェント(Spring AOP)

21707 ワード

記事の目次
  • 、AOPは何ですか?
  • 、スタティックエージェント、AsppectJ
  • 2.1、例示
  • 、動的エージェント
  • 3.1、JDKダイナミックエージェント
  • 3.1.1、コアクラス:
  • 3.1.2、例1−JDK動的エージェント
  • 3.2、CGLOIB動的エージェント
  • 3.2.1コアクラス:
  • 3.2.2、例
  • 、小結
  • 一、AOPは何ですか?
    ここのAOPはSpring AOPではなく、面に向かってプログラミングする思想を指します.
    AOP(Aspect Orient Prograamming)は、一般的には、指向プログラミングと呼ばれ、対象に向けた補足として、処理システムにおいて各モジュールに分布する横断的な注目点、例えば、事務管理、ログ、キャッシュなどに用いられます.
    AOP実装は主に静的エージェントと動的エージェントに分けられる.
  • 静的エージェントは、主にAspectJ
  • である.
  • 動的エージェントは主にSpring AOP
  • である.
    本論文はAspectJとSpring AOPの実現をそれぞれ分析して紹介します.
    二、スタティックエージェント——AsppectJ
    AsppectJの基礎技術は静的エージェントであり、AsppectJがサポートする特定の言語で切断面を作成し、コマンドをコンパイルして、新しいエージェントクラスを生成します.このエージェントはビジネスクラスを強化しています.
    2.1、例を挙げて説明する
    まず普通のハロークラスがあります.
    ハロークラス:
    public class Hello {
        public void sayHello() {
            System.out.println("hello");
        }
     
        public static void main(String[] args) {
            Hello h = new Hello();
            h.sayHello();
        }
    }
    
    AsppectJを使ってAsppectを作成します.
    TxAspectクラス:
    public aspect TxAspect {
        void around():call(void Hello.sayHello()){
            System.out.println("     ...");
            proceed();
            System.out.println("     ...");
        }
    }
    
    ここではSpringのような事務の場面をシミュレーションした.AsppectJのコンパイラを使ってコンパイルします.
    ajc -d . Hello.java TxAspect.aj
    
    コンパイルが完了したら、このハロークラスを実行します.以下の出力が見られます.
         ...
    hello
         ...
    
    明らかに、AOPはすでに発効しました.一体、AsppectJはHello類を修正しないで、ハロー類のために新しい機能を追加したのですか?
    コンパイル後のHello.class
    public class Hello {
        public Hello() {
        }
     
     	public void sayHello() {
            System.out.println("hello");
        }
     
        public static void main(String[] args) {
            Hello h = new Hello();
            sayHello_aroundBody1$advice(h, TxAspect.aspectOf(), (AroundClosure)null);
        }
    }
    
    これはAsppectJのスタティックエージェントであり、コンパイル段階でAsppectをJavaバイトコードに編入し、実行する時は強化された後のAOPオブジェクトである.
    Asppectコンパイル後のクラスファイル
    public void ajc$around$com_listenzhangbin_aop_TxAspect$1$f54fe983(AroundClosure ajc$aroundClosure) {
            System.out.println("     ...");
            ajc$around$com_listenzhangbin_aop_TxAspect$1$f54fe983proceed(ajc$aroundClosure);
            System.out.println("     ...");
    }
    
    Asppectがコンパイルした後のclassファイルから、実行の論理がより明確に見られます.プロシージャ方法は、被プロキシクラスをリピートして実行する方法です.
    三、ダイナミックエージェント
    Spring AOPで使用する動的エージェントとは、AOPフレームがバイトコードを修正することなくメモリに一時的にAOPオブジェクトを生成するということであり、このAOPオブジェクトはターゲットオブジェクトのすべての方法を含み、特定の接点で強化処理を行い、元のオブジェクトを調整する方法である.
    Spring AOPにおける動的エージェントは主に2つの方法があります.JDKダイナミックエージェントとCGLOIBダイナミックエージェントです.
    3.1、JDKダイナミックエージェント
    JDK動的エージェントは、反射によってプロキシされたクラスを受信し、プロキシが要求されるクラスは、インターフェースを実装しなければならない.
    3.1.1、コアクラス:
  • InvocationHandlerインターフェース
  • Proxy.newProxyInstance()
  • 3.1.2、例1–JDKダイナミックエージェント
    Personインターフェースを定義します.
    public interface Person {
        String sayHello(String name);
    }
    
    実現クラス–中国人:
    @Component
    public class Chinese implements Person { 
    
        @Timer
        @Override
        public String sayHello(String name) {
            System.out.println("-- sayHello() --");
            return name + " hello, AOP";
        }
     
        public void eat(String food) {
            System.out.println("    :" + food);
        } 
    }
    
    ここの@Timer注解は自分で定義した普通の注釈で、Pointcutをマークします.
    Asppectを定義する
    @Aspect
    @Component
    public class AdviceTest {
     
        @Pointcut("@annotation(com.listenzhangbin.aop.Timer)")
        public void pointcut() {
        }
     
        @Before("pointcut()")
        public void before() {
            System.out.println("before");
        }
    }
    
    テスト:
    @SpringBootApplication
    @RestController
    public class SpringBootDemoApplication {
     
        //      Person     
        @Autowired
        private Person chinese;
     
        @RequestMapping("/test")
        public void test() {
            chinese.sayHello("listen");
            System.out.println(chinese.getClass());
        }
     
        public static void main(String[] args) {
            SpringApplication.run(SpringBootDemoApplication.class, args);
        }
    }
    
    出力:
    before
    -- sayHello() --
    class com.sun.proxy.$Proxy53
    
    このタイプはcomp.sun.proxy 53であり、前述のProxy類であるため、Spring AOPはJDK を使用しています.
    3.2、CGLOIBダイナミックエージェント
    ターゲットクラスがインターフェースを実現していない場合、Spring AOPはCGLOIBを使用してターゲットクラスを動的に代理することを選択します.
  • CGLOIB(Code Generation Library)は、コード生成のクラスであり、実行時にあるクラスのサブクラスを動的に生成することができる.
  • CGLOIBは によって動的エージェントを行うので、あるクラスがfinalとしてマークされている場合、CGLOIBを動的エージェントとして使用することはできない.
  • 3.2.1コアクラス:
  • MethodInterceptorインターフェース
  • Enhancer類
  • 3.2.2、例
    @Component
    public class Chinese {   
    
        public String sayHello(String name) {
            System.out.println("-- sayHello() --");
            return name + " hello, AOP";
        }
     
        public void eat(String food) {
            System.out.println("    :" + food);
        } 
    }
    
    テスト:
    @SpringBootApplication
    @RestController
    public class SpringBootDemoApplication {
     
        //   Chinese   
        @Autowired
        private Chinese chinese;
     
        @RequestMapping("/test")
        public void test() {
            chinese.sayHello("listen");
            System.out.println(chinese.getClass());
        }
     
        public static void main(String[] args) {
            SpringApplication.run(SpringBootDemoApplication.class, args);
        }
    }
    
    出力:
    before
    -- sayHello() --
    class com.listenzhangbin.aop.Chinese$$EnhancerBySpringCGLIB$$56b89168
    
    CGLOIBによってクラスが強化された、すなわちCGLOIB動的エージェントが見られます.ここのCGLOIBエージェントはSpring AOPの代理であり、このクラスはいわゆるAOPエージェントであり、AOPエージェント類は接点で動的に補強処理に織り込まれている.
    四、結び
    AspectJはコンパイル時にターゲットオブジェクトを強化し、Spring AOPの動的エージェントは運行毎に動的に強化され、AOPエージェントオブジェクトを生成する.
    AOPプロキシを生成するタイミングが違っていて、AsppectJのスタティックエージェント方式はより良い性能を持っていますが、AspectJは特定のコンパイラを必要とします.Spring AOPは特定のコンパイラ処理を必要としません.