デザインモードのダイナミックエージェント


一、ダイナミックエージェント概念
動的エージェントはJDK動的エージェントとcglib動的エージェントの2つの方法に分けられる。
jdk動的エージェントはJava内部の反射機構によって実現され、cglib動的エージェントの下の層はasmによって実現される。
全体的には、クラスを生成する過程で反射機構が効率的であり、asmはクラスを生成した後の関連実行過程で比較的効率的である(asmを生成したクラスをキャッシュすることにより、asm生成クラスのプロセスの効率的な問題を解決することができる)。
もう一つ注意しなければなりません。jdkダイナミックエージェントの応用前提は、ターゲットクラスが統一されたインターフェースに基づいている必要があります。上記の前提がないと、jdkダイナミックエージェントは適用できません。
このことから、jdk動的エージェントは一定の限界があり、cglibのような第三者クラスで実現される動的エージェントアプリケーションはより広く、効率的に優れていることが分かる。
二、JDKダイナミックエージェント
以下のコードは、プロキシモードを使用して、大文字と小文字の変換機能を実現します。
インターフェースと実装クラスを定義します。
ISome Serviceインターフェース:

package com.ietree.basicskill.designpattern.dynamicproxy.jdk;

/**
 *    
 * 
 * @author Root
 */
public interface ISomeService {
  
  String doFirst();
  
  void doSecond();
}
SomeServiceImpl実現クラス:

package com.ietree.basicskill.designpattern.dynamicproxy.jdk;

/**
 *    
 * 
 * @author Root
 */
public class SomeServiceImpl implements ISomeService {

  @Override
  public String doFirst() {
    System.out.println("  doFirst()...");
    String result = "abcde";
    return result;
  }

  @Override
  public void doSecond() {
    System.out.println("  doSecond()...");
  }

}
JDKダイナミックエージェント:

package com.ietree.basicskill.designpattern.dynamicproxy.jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Main {
  public static void main(String[] args) {

    final ISomeService target = new SomeServiceImpl();
    
    //   JDK Proxy    ,                  ,                  
    ISomeService service = (ISomeService) Proxy.newProxyInstance(
        //         
        target.getClass().getClassLoader(),
        //            
        target.getClass().getInterfaces(), 
        new InvocationHandler() {
          // proxy:    
          // method:    
          // args:         
          @Override
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //       
            Object result = method.invoke(target, args);
            if (result != null) {
              result = ((String) result).toUpperCase();
            }
            return result;
          }
        });
    String result = service.doFirst();
    System.out.println(result);

    service.doSecond();
  }
}
三、cglibダイナミックエージェント
Cglibは優れた動的エージェントフレームであり、その最下部はASMを使用してメモリ内で動的にプロキシクラスのサブクラスを生成し、CGLOBを使用してプロキシクラスが実装されていなくても動的エージェント機能を実現することができる。CGLOIBは簡単で使いやすいです。その運行速度はJDKのProxyダイナミックエージェントより遥かに速いです。
CGLOIBのコアクラス:
net.sf.cglib.proxy.Enhancer Cの主な強化類
net.sf.cglib.proxy.MethodInterceptor Cの主な方法はクラスをブロックして、それはCallbackインターフェースのサブインターフェースで、ユーザーが実現する必要があります。
net.sf.cglib.proxy.MethodProxy C JDKのjava.lang.reflect.Method類のエージェントクラスは、ソースオブジェクト方法の呼び出しを簡単に実現することができます。
Object o=methodProxy.invokeSuper;最初のパラメータはプロキシ対象ですが、デッドサイクルの問題はありません。
net.sf.cglib.proxy.MethodInterceptrインターフェースは最も一般的なコールバックタイプであり、それはよくエージェントのAOPに基づいてブロッキング方法の呼び出しを実現するために使われる。このインターフェースは一つの方法だけを定義しています。
public Object intercept(Object Object、java.lang.reflect.Method method、Object[]args、Methodoxy proxy)throws Throwable;
最初のパラメータはプロキシ対像であり、第二及び第三のパラメータはそれぞれブロッキングの方法と方法のパラメータである。元々の方法は、java.lang.reflect.Methodオブジェクトの一般的な反射呼び出しを使用するか、net.s.cglib.proxy.MethodProxyオブジェクトを使用して呼び出されるかもしれない。net.sf.cglib.proxy.MethodProxyは一般的に優先的に使われています。
以下のプログラムは、大文字小文字変換の機能を実現しました。
実現クラスSomeService:

package com.ietree.basicskill.designpattern.dynamicproxy.cglib;

/**
 *    
 * 
 * @author Root
 */
public class SomeService {

  public String doFirst() {
    System.out.println("  doFirst()...");
    String result = "abcde";
    return result;
  }

  public void doSecond() {
    System.out.println("  doSecond()...");
  }

}
代理種類MyCglibFactory:

package com.ietree.basicskill.designpattern.dynamicproxy.cglib;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class MyCglibFactory implements MethodInterceptor {

  private SomeService target;
  
  public MyCglibFactory() {
    super();
    target = new SomeService();
  }

  public SomeService myCglibCreator() {
    //        
    Enhancer enhancer = new Enhancer();
    //      ,   
    enhancer.setSuperclass(SomeService.class);
    //         
    enhancer.setCallback(this);

    return (SomeService) enhancer.create();
  }

  @Override
  public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
    //       
    Object result = method.invoke(target, args);
    if (result != null) {
      result = ((String) result).toUpperCase();
    }
    return result;
  }

}
テスト:

package com.ietree.basicskill.designpattern.dynamicproxy.cglib;

public class Main {
  public static void main(String[] args) {

    SomeService service = new MyCglibFactory().myCglibCreator();
    
    String result = service.doFirst();
    System.out.println("result = " + result);

    service.doSecond();
  }
}
実行結果:

  doFirst()...
result = ABCDE
  doSecond()...
以上のこのありふれたデザインの動的代理は小編集が皆さんに提供した内容の全部です。参考にしていただければと思います。よろしくお願いします。