切面向けプログラミング(AOP)


Aspect Oriented Programming(AOP)は、カットプログラミング向けで、比較的人気のある話題です.AOPの主な目的は、論理プロセスの各部分間の低結合性の分離効果を得るために、プロセス中のあるステップまたは段階に直面するビジネスプロセス中の断面を抽出することである.例えば、私たちが最もよく見られるのはログ記録です.例を挙げると、私たちは今、学生情報を検索するサービスを提供していますが、誰がこのクエリーを行ったかを記録したいと思っています.従来のOOPの実装に従えば、学生情報を問い合わせるサービスインタフェース(StudentInfoService)とその実装クラス(StudentInfoServiceImport.java)を実装し、記録するために実装クラス(StudentInfoServiceImport.java)に実装レコードを追加するプロセスを実装します.そうすると、もし私たちが実現するサービスが複数あるとしたら?では、実装されたクラスごとにこれらのレコードプロセスを追加します.これにより少し煩雑になり,各実装クラスはサービスログを記録する行為と密接に結合し,オブジェクト向けのルールに違反する.では、どのようにして記録サービスの行為と業務処理の過程を分離することができますか?学生を検索するサービスは自分で行っているように見えますが、背後のログはこれらの行為を記録していますが、学生を検索するサービスはこれらの記録過程があることを知りません.これがAOPの目的です.AOPのプログラミングは,我々のある側面での機能を一組のオブジェクトから分離することで,一組のオブジェクトとの結合性を低下させ,ある機能についてプログラミングすることができるようになった.
   コードから直接始めましょう.以上の目標を達成するには、動的エージェントクラス(Proxy)を使用して、オブジェクトの動作をブロックし、必要な機能を追加することで達成することができます.Javaのjava.lang.reflect.Proxyクラスとjava.lang.reflect.InvocationHandlerインタフェースは、動的エージェントクラスを実装するためのスキームを提供しますが、このスキームはオブジェクトに対していくつかのインタフェースを実装します.目的がクラスであれば、cglibは別の実装案を提供してくれます.あとで両者の違いを説明します.
一、インタフェースの実現方案:
1)まず、デルのビジネスインタフェース(StudentInfoService.java)を作成します.

//~~StudentInfoService.java
public interface StudentInfoService{
    void findInfo(String studentName);
}

//~~    StudentInfoServiceImpl.java
public class StudentInfoServiceImpl implements StudentInfoService{
   public void findInfo(String name){
     System.out.println("         :"+name);
   }
}

2)findInfo動作の前にその動作を実行して記録するログ機能が必要になります.まず、その動作をブロックします.実際に実行する過程でエージェントクラスで私たちの代わりに完了します.Javaでは、動的エージェントクラスを実装するためのシナリオを提供しています.

//~~         MyHandler.java
import org.apache.log4j.Logger;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.lang.reflect.Method;

public class MyHandler implements InvocationHandler{
  private Object proxyObj;
  private static Logger log=Logger.getLogger(MyHandler.class);
  public Object bind(Object obj){
      this.proxyObj=obj;
      return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this);
  }
  public Object invoke(Object proxy,Method method,Object[] args)  throws Throwable{
      Object result=null;
      try{
     //        ,      
           log.info("  log    "+method.getName());
          result=method.invoke(proxyObj,args); //   
            //        ,     
       }catch(Exception e){
          e.printStackTrace();
      }
      return result;
  }
}

//~~        ,             AOPFactory.java
public class AOPFactory{
    private static Object getClassInstance(String clzName){
     Object obj=null;
     try{
         Class cls=Class.forName(clzName);
         obj=(Object)cls.newInstance();
     }catch(ClassNotFoundException cnfe){
         System.out.println("ClassNotFoundException:"+cnfe.getMessage());
     }catch(Exception e){
         e.printStackTrace();
     }
     return obj;
    }

    public static Object getAOPProxyedObject(String clzName){
      Object proxy=null;
      MyHandler handler=new MyHandler();
      Object obj=getClassInstance(clzName);
      if(obj!=null) {
         proxy=handler.bind(obj);
      }else{
      System.out.println("Can't get the proxyobj");
     //throw
      }
      return proxy;
    }
}
3)基本的なブロックとその工場はすべて実現して、今テスト(ClientTest.java):

public class ClientTest{
    public static void main(String[] args){
    StudentInfoService studentInfo=(StudentInfoService)     AOPFactory.getAOPProxyedObject("StudentInfoServiceImpl");
studentInfo.findInfo("  ");
    }
}
出力結果(log 4 j設定を参照):
logログメソッドfindInfoを呼び出す
あなたが今入力している名前は「飛」です.
これで私たちが必要とする効果が出て、ビジネス処理は自分で行われていますが、ログ機能を実現しました.ビジネス処理(StudentInfoService)はその行為があることを知りません.しかし、Javaで提供される動的エージェントクラスの実装は、いくつかのインタフェースを実装したクラスに対して行われており、実装インタフェースがなければ、エージェントクラスを作成することはできません.上記のセクションを参照してください.

return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this);
見たか?obj.getClass().getInterfaces()は、いくつかのインタフェースを実装する必要があります.以下に、実装インタフェースのない実装スキームを示します.
二、サブクラスの実現方案.
まず、インターネットでCGLibのパッケージをダウンロードしてください.http://sourceforge.net/project/showfiles.php?group_id=56933 .classpathパスを設定し、CGLibはjava標準ライブラリが提供する実装スキームとは異なり、cglibは主に実装クラスに基づいている.StudentInfoServiceImpl.javaのように、サブクラスを拡張して実装します.net.sf.cglib.proxy.EnhancerおよびMethodInterceptorは、Dynamic ProxyのProxyおよびInvocationHandlerに対応して、CGLibでエージェントオブジェクトの作成およびメソッドキャプチャ処理を完了し、インタフェースでメソッドブロックを実装するのではなく、ターゲットクラスのサブクラスを生成します.Enhancerは主に動的世代を構築するために使用されます.ブロックを実装するために理子クラスが使用され、MethodInterceptor(Callbackインタフェースを拡張)は主にaround advice(AOPの概念)を実装するために使用されます.
1)当社の業務処理(StudentInfoServiceImpl.java):

//~~StudentInfoServiceImpl.java
public class StudentInfoServiceImpl{
public void findInfo(String name){
System.out.println("         :"+name);
}
}
2)ログ機能(AOPINstrumenter.java)を処理するためのツールを実行する.

//~~AOPInstrumenter.java
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import org.apache.log4j.Logger;
public class AOPInstrumenter implements MethodInterceptor{
private Logger log=Logger.getLogger(AOPInstrumenter.class);
private Enhancer enhancer=new Enhancer();
public Object getInstrumentedClass(Class clz){
enhancer.setSuperclass(clz);
enhancer.setCallback(this);
return enhancer.create();
}
public Object intercept(Object o,Method method,Object[] args,MethodProxy proxy) throws Throwable{
log.info("      "+method.getName());
Object result=proxy.invokeSuper(o,args);
return result;
}
}
3)テストしてみましょう(AOPTest.java):

//~~AOPTest.java
public class AOPTest{
public static void main(String[] args){
AOPInstrumenter instrumenter=new AOPInstrumenter();
StudentInfoServiceImpl studentInfo=(StudentInfoServiceImpl)instrumenter.getInstrumentedClass(StudentInfoServiceImpl.class);
studentInfo.findInfo("  ");
}
}
出力結果は以上と同じです.
CGLibでは以上の目的を達成するために主に提供されるクラス
1)Enhancer:setCallback(Callback)、setSuperclass(Class)、create()動的サブクラスObjectを返す
2)MethodInterceptorが実装しなければならないインタフェース:intercept(Object,Method,Object[],MethodProxy)は、元のメソッド呼び出しの結果を返します.Proxyと同じ原理です.
三、以上の二つの簡単なAOPを実現する方案はすべてあなたのために準備して、あなたは自分でテストを書くことができて、以下は簡単にAOPの基本的な概念を紹介します:
1)aspect(接面):cross-cutting機能を実現し、接面に対するモジュールである.最も一般的なのはloggingモジュールです.このように、プログラムは機能別にいくつかの階層に分けられています.従来の継承では、ビジネスモデル継承ログモジュールでは意味がありませんが、loggingカットを作成することでAOPを使用して同じ機能を実現することができます.
2)jointpoint(接続点):接続点は、メソッドによって呼び出され、意外に投げ出される接面挿入アプリケーションの場所です.接続ポイントは、アプリケーションが接面に挿入する場所であり、新しい方法を追加することができます.例えば,我々の接点はfindInfo(String)法と考えられる.
3)advice(処理ロジック):adviceは我々の切面機能の実現であり、プログラムに新しい行為を通知する.loggingでは、logging adviceには、ログをファイルに書き込むようなloggingの実装コードが含まれます.adviceはjointpointでアプリケーションに挿入されます.以上、MyHandler.javaでadviceの機能を実現しました
4)pointcut(接点):pointcutは、jointpointにどのadviceを適用するかを制御します.通常、pointcutsを使用して正規表現で明らかな名前とモードをマッチングします.そのjointpointが通知を受けることが決まった.
5)introduction:クラスに新しいメソッドと属性を追加できます.
6)target(ターゲットクラス):adviceを使用するクラスを指し、一般的には独立したビジネスモデルを指す.例えば、上記のStudentInfoServiceImpl.
7)proxy(エージェントクラス):proxyを使用したモード.adviceが適用されたオブジェクトで、targetオブジェクトに似ているように見えます.
8)weaving(挿入):targetオブジェクトにaspectsを適用してproxyオブジェクトを作成するプロセス:complie time,classload time,runtime