Spring AOPの代理機構


早くからspring aopと聞いていますが、ずっと静かに勉強していませんでした.今日は「springに詳しい」を見て、私が理解しているspring aopをメモしてみました.もちろん、まず何がAOPですか?AOP(Aspect Oriented Prograamming)は、方面に向けてプログラミングされていますが、springにとっては「指向プログラミング」と解釈するのがより正確です.どうしてAOPを使うのですか?みんなはすべてOOP(Oriented Object Programming)が対象に向かってプログラミングすることを知っています.ここでは主に継承について説明したいのですが、複数の種類が同じ属性や方法を持っているなら、私たちは親の定義を考えます.そして、そのサブクラスを継承します.例えば、Animalはrun()、eat()という二つの抽象的な方法を持つ父類を定義し、rabbit、horseはAnimal類を継承してrun()を書き換えます.
eat()は、親類を引用して重複コードを消去します.多くのことを言いましたが、spring aopを導入するために、みんなの属性のコードを見てみます.
package com.me.services.imp;

import com.me.entity.User;
import com.me.services.UserService;
import com.me.daos.UserDAO;
import com.me.util.TransationManager;
import com.me.util.PerformanceMonitor;

public class UserServiceImp implements UserService {
    private TransationManager trans = new TransationManager();
    private PerformanceMonitor pmonitor = new PerformanceMonitor();
    private UserDAO userDao = new UserDAO();
    
	public void deleteUser(int userId) {
		pmonitor.start("com.me.services.imp.UserServiceImp.deleteUser");//1 trans.beginTransation();//2
		userDao.deleteUser(userId);
		trans.commitTransation(); pmonitor.end();
	}

	public void insertUser(User user) {
		pmonitor.start("com.me.services.imp.UserServiceImp.insertUser");//1
		trans.beginTransation();//2
		userDao.inserUser(user);
		trans.commitTransation();
		pmonitor.end();
	}

}
このコードは、追加ユーザの性能を監視し削除するためのもので、業務ロジック以外に、大量の事務処理と性能監視重複コード(1、2コード)、
それは親の抽象的なものでもありますか?もちろんダメです.継承は縦割りの仕組みです.ここではAOP横カットを使って独立したモジュールを抽出します.
まとめ:AOP運用の場合は、性能監視、アクセス制御、事務処理、ログ記録があります.
 
Spring AOPを勉強して、まずいくつかのAOP関連の重要な用語をマスターします.以下は私の理解です.異議があれば、お互いに相談してもいいです.
接続ポイント(Joinpoint):プログラムの実行点です.クラス初期化前、後、メソッド呼び出し前、後など.
カットポイント(Pointcut):ある方法を位置づけて、org.springframe ebook.aop.Pointcutインターフェースを通じて説明します.
追加(Advice):ターゲットクラスの接続点に織り込むコードの一部.springは前置増強、後付け増強、異常増強、サラウンド強化の四つのタイプを提供します.
ターゲット:ビジネスロジッククラス.
紹介(Introduction):特殊な強化で、業務クラスのために動的に実現インターフェースを追加することができます.このインターフェースを業務クラスに実現させる.
編入(Weaving):目標クラスに追加するプロセスを強化する.コンパイル期間に分けて編入し、クラス積期に編入し、動的代理で編入します.springは動的エージェントを採用しています.前の二つは特殊なjavaコンパイラとクラスローダーが必要です.
代理(Proxy):業務ロジック類と強化された代理類を融合させました.
切断面(Asppect):切断点と強化構成があります.後に述べる.
 
上で述べたspring aopはダイナミックエージェント方式で織り込まれていますが、何がダイナミックエージェントですか?運転期間に目標クラスにサブクラスを追加して生成する方式です.ダイナミックエージェントはまたそれらに分けられますか?JDKダイナミックエージェント(インターフェースを介してプロキシを作成)、CGlibダイナミックエージェント(クラス作成エージェントを介して).
 
JDKダイナミックエージェントは、Java.lang.reflectパッケージのProxy類とInvocationHandleインターフェースを使用しています.InvocationHandleインターフェースを実現することによって、横方向論理を定義し、反射メカニズムを通してターゲットクラスのコードを呼び出します.Proxyはターゲットクラスの代理オブジェクトを生成するために使用される.次のコードを見ます.
コードの一部を1、2コードの部分から削除します.
	public void deleteUser(int userId) {
		//pmonitor.start("com.me.services.imp.UserServiceImp.deleteUser");
		//trans.beginTransation();
		userDao.deleteUser(userId);
		//trans.commitTransation();
		//pmonitor.end();
	}

	public void insertUser(User user) {
		//pmonitor.start("com.me.services.imp.UserServiceImp.insertUser");
		//trans.beginTransation();
		userDao.inserUser(user);
		//trans.commitTransation();
		//pmonitor.end();
	}
 
JDKダイナミックエージェントはインターフェースを通じて代理を作成するので、InvocationHandleインターフェースを実現するように定義して、業務コードとクロスコード編みの作成代理例を完成します.
package com.me.util;

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

public class PerformanceHandler implements InvocationHandler {

	private Object target;
	
	public PerformanceHandler(Object target){
		this.target = target;
	}
	/**
	 * @param proxy          ,      
	 * @param method            ,             
	 * @param args           ,        
	 */
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		//           
		PerformanceMonitor pMonitor = new PerformanceMonitor();
		//               ,   +  +   
		pMonitor.start(target.getClass().getName()+"."+method.getName());
		//                ,        
		Object obj = method.invoke(target,args);
		pMonitor.end();
		return obj;
	}

}
 
試験種別の作成:
package com.me.test;

import com.me.entity.User;
import com.me.services.UserService;
import com.me.services.imp.UserServiceImp;
import com.me.util.PerformanceHandler;
import java.lang.reflect.Proxy;

public class TestUserService {
 
	public static void main(String[] args) {
        //  JDK       
		UserService target = new UserServiceImp();//         
		PerformanceHandler handler = new PerformanceHandler(target);
		//          InvocationHandler              
		UserService proxy = (UserService)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler);
		//   :        :               :              
		proxy.deleteUser(1);
		User user = new User();
		proxy.insertUser(user);
	}
 JDKダイナミックエージェントはインターフェースを通して業務方法の種類を定義することを知っています.インターフェースを使わずに業務クラスを定義します.私たちはCGibを使って動的に代理を作成します.
CGlibは非常に低いバイトコード技術を採用しており、一つのクラスのためにサブクラスを作成し、サブクラスにおいて方法でブロックする技術を採用して親類方法の呼び出しを遮り、その勢いに従ってクロスカットロジックに織り込むことができる.セグメントコードを見てみます.
package com.me.util;

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 CglibProxy implements MethodInterceptor {
	//      enhancer,    ,       Enhancer          ,     callback proxy,                     MethodInterceptor   proxy intercept()   
    private Enhancer enhancer = new Enhancer();
    
    @SuppressWarnings("unchecked")
	public Object getProxy(Class clazz){
    	enhancer.setSuperclass(clazz);
    	enhancer.setCallback(this);
    	return enhancer.create();
    }
	public Object intercept(Object target, Method method, Object[] args,
			MethodProxy proxy) throws Throwable {
		PerformanceMonitor pm = new PerformanceMonitor();
		pm.start(target.getClass().getName()+"."+method.getName());
		//             
		Object obj = proxy.invokeSuper(target,args);
		pm.end();
		return obj;
	}

}
 cglibをテストして動的エージェントを作成します.
package com.me.test;

import com.me.entity.User;
import com.me.services.UserService;
import com.me.services.imp.UserServiceImp;
import com.me.util.CglibProxy;

public class TestUserService {
 
	public static void main(String[] args) {
		//cglib      
		CglibProxy proxy = new CglibProxy();
		UserService service = (UserServiceImp)proxy.getProxy(UserServiceImp.class);
		service.deleteUser(1);
		service.insertUser(new User());
	}
}
 
コンソール出力では、我々は"EnhancerByCGLOIB$e 28373 d 6"を見ることができます.これはcglib動的に作成されたサブクラスです.
 
二つの動的エージェントはどうやって取捨選択しますか?
cglibはjdkよりダイナミックエージェントを作成する性能が約10倍高いが、cglibはエージェントを作成する時間がjdkより8倍多い.したがって、singletonまたは例示的な池オブジェクトエージェントを作成するにはcglib方式が適切であり、頻繁にエージェントオブジェクトを作成する必要はないが、cglibは動的にサブクラスを作成する方式でプロキシオブジェクトを生成するので、ターゲットクラスにおけるfinal方法をプロキシする.
 
上記のコードは全部ではなく、使用するコード類をアップロードします.