1. 程式人生 > >(13)Spring學習記錄---Spring_bean(AOP基礎)

(13)Spring學習記錄---Spring_bean(AOP基礎)

先來實現一個例項 

 

1.建立介面ArithmeticCalulator

public interface ArtithmeticCaclulator {
	int add(int i,int j);
	int sub(int i,int j);
	
	int mul(int i,int j);
	int div(int i,int j);
}

2.實現ArithmeticCalulatorImpl,並加入日誌資訊

public class ArithmeticCalulatorImpl implements ArtithmeticCaclulator {

	@Override
	public int add(int i, int j) {
		System.out.println("The method add 	begin with [" + i + "," + j + "]");
		int result = i + j;
		System.out.println("The method add 	end with " + result);
		return result;
	}

	@Override
	public int sub(int i, int j) {
		System.out.println("The method sub 	begin with [" + i + "," + j + "]");
		int result = i - j;
		System.out.println("The method sub 	end with " + result);
		return result;

	}

	@Override
	public int mul(int i, int j) {
		System.out.println("The method mul 	begin with [" + i + "," + j + "]");
		int result = i * j;
		System.out.println("The method mul 	end with " + result);
		return result;

	}

	@Override
	public int div(int i, int j) {
		System.out.println("The method div 	begin with [" + i + "," + j + "]");
		int result = i / j;
		System.out.println("The method div 	end with " + result);
		return result;

	}

}

3.Main

public class Main {
	public static void main(String[] args) {
		
		
		ArtithmeticCaclulator artithmeticCaclulator =new ArithmeticCalulatorImpl();
		
		int result=artithmeticCaclulator.add(1, 2);
		System.out.println("->>"+result);
		
		result=artithmeticCaclulator.sub(3, 2);
		System.out.println("->>"+result);
	}
}

4.結果

可以看到這些日記資訊都十分相似,而且當我加入這些日誌資訊後,有時候會和業務程式碼混淆,難以區分。不利於我們的維護。

解決方法一:

1.動態代理

AritimeticCalulatorLoggingProxy.class

public class AritimeticCalulatorLoggingProxy {
	
	//要代理的物件
	private ArtithmeticCaclulator target;
	
	public AritimeticCalulatorLoggingProxy(ArtithmeticCaclulator target) {
		this.target = target;
	}

	public ArtithmeticCaclulator getLoggingProxy() {
		ArtithmeticCaclulator proxy=null;
		
		//代理物件由哪個類載入器載入
		ClassLoader loader=target.getClass().getClassLoader();	
		
		//代理物件的型別 包括其中的方法
		Class  [] interfaces =new Class[] {ArtithmeticCaclulator.class};
		
		//當呼叫代理物件的方法時 指向的程式碼
		InvocationHandler h =new InvocationHandler() {
			
			/**
			 * 	proxy:正在返回的那個代理物件 一般情況下 在invoke方法總都不使用該物件
			 * 	method:正在被呼叫的方法
			 * 	args:呼叫方法的引數
			 * **/
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				String methodname=method.getName();
				//日誌
				System.out.println("The method "+ methodname	+" begin with "+	Arrays.asList(args));
				//執行方法
				Object result  = method.invoke(target, args);
				//日誌
				System.out.println("The method "+ methodname +	" end with " + result);
				return result;
			}
		};
		
		
		proxy=(ArtithmeticCaclulator)Proxy.newProxyInstance(loader, interfaces, h);
		
		return proxy;
	}
}

 我們把公共程式碼寫在InvocationHandler裡面。同時去除ArithmeticCalulatorImpl的日誌資訊。

修改Main方法 ,通過代理呼叫方法

public class Main {
	public static void main(String[] args) {
		
		ArtithmeticCaclulator target=new ArithmeticCalulatorImpl();
		ArtithmeticCaclulator proxy= new AritimeticCalulatorLoggingProxy(target).getLoggingProxy();
		
		
		int result=proxy.add(1, 2);
		System.out.println("->>"+result);
		
		result=proxy.sub(3, 2);
		System.out.println("->>"+result);
		
	}
}

結果:

 

我們可以引入這樣一種思想,將業務程式碼和日誌程式碼以某種形式分離開來,由於他們是同一層的(橫向的),所有我們可以像上面的例子用Proxy分離。但是實際中肯定不能這麼做,一是維護成本高,二是對程式設計師要求也高。

我們可以利用Aop程式設計的思想來解決程式碼分離的問題。

AOP簡介

 

術語

1.切面:我們將日誌抽取出來,作為一個切面,將驗證抽取出來,作為一個切面,將業務邏輯抽取出來,作為一個切面。這些切面都叫做橫切關注點。

2.通知:切面裡的每一個方法都是一個通知。它是每個切面必須完成的工作。

3.目標:被通知的物件,這裡是add(),mul(),div(),sub()。

4.代理:通知目標後,業務邏輯和日誌必須有一個結合,這樣的結果就是產生一個代理。

5.連線點:以方法執行為評判標準,執行前後中,異常丟擲時等等。。相當於一個被查詢的資料。是切點的定位目標

6.切點:aop通過切點定位到連線點,看不見摸不著。相當於查詢條件。