spring--(15)AOP基礎

需求:有一個接口,裏面有多個方法,如今須要記錄每一個方法的開始與結束。
//接口以下java

public interface Calculator {
	int add(int i,int j);
	int sub(int i,int j);
	
}

//接口實現以下程序員

public class CalculatorImpl implements Calculator{

	@Override
	public int add(int i, int j) {
		int result = i+j;
		return result;
	}

	@Override
	public int sub(int i, int j) {
		int result = i-j;
		return result;
	}

}

1.常規作法,在每一個方法的開始與結束的地方加上log。以下spring

public class CalculatorImpl implements Calculator{

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

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

}

1.1 測試代碼數據庫

public class Main {
	public static void main(String[] args) {
		Calculator calculator = new CalculatorImpl();
		calculator.add(1, 2);
		calculator.sub(4, 2);	
	}
}

1.2 輸出結果編程

The method add begin[1,2]
The method add end3
The method sub begin[4,2]
The method sub end2

2.很明顯上述能夠知足每一個方法執行先後輸出log的要求,可是若是輸出的內容稍微改一點,那麼將是大面積的修改log,所以上述方法不是很適合大型項目的log需求。
2.1 採用動態代理方法實現,添加代理類框架

package com.test.aop;

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

public class CalculatorProxy {
	
	//要代理的對象
	private Calculator target;
	//返回代理對象
	public Calculator getProxy(){
		Calculator proxy = null;
		
		//代理對象由哪個類加載器負責加載
		ClassLoader loader = target.getClass().getClassLoader();
		//代理對象的類型,即其中有哪些方法
		Class [] interfaces = new Class[]{Calculator.class};
		//當調用代理對象的方法時,執行該代碼
		InvocationHandler h = new InvocationHandler() {
			/**
			 * proxy:正在執行的代理對象,通常不使用該對象
			 * 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 "+Arrays.asList(args));
				//執行方法
				Object oj = method.invoke(target, args);
				//日誌結束
				System.out.println("The method"+methodName+" end "+oj);
				return oj;
			}
		};
		proxy = (Calculator) Proxy.newProxyInstance(loader, interfaces, h);
		
		return proxy;
	}
	public CalculatorProxy(Calculator target) {
		this.target = target;
	}
}

2.2 main方法ide

public class Main {
	
	public static void main(String[] args) {
		
		Calculator target = new CalculatorImpl();
		Calculator proxy = new CalculatorProxy(target).getProxy();
		int result = proxy.add(1, 2);
		System.out.println(result);
		result = proxy.sub(4, 2);
		System.out.println(result);
	}
}

2.3輸出測試

The methodadd begin [1, 2]
The methodadd end 3
3
The methodsub begin [4, 2]
The methodsub end 2
2

3.如上的方法徹底能夠知足需求,可是不可能每一個程序員都懂動態代理,加之spring框架自己也提供了相應的解決方法,即AOP(面向切面編程)。舉個簡單的實例,一個業務邏輯由以下部分組成:
1>驗證參數
2>前置日誌
3>方法,即核心實現
4>後置日誌
AOP經常使用術語:
1.切面:如上業務邏輯組成部分,每一個點都是一個切面。
2.通知:切面完成的功能。
3.目標:被通知的對象,即如上業務邏輯組成部分中的 方法。
4.代理:它是一個對象,它的做用是通知目標對象。
5.鏈接點:指的是程序的某個位置,例如:某個方法被調用以前、調用以後,或是拋出異常的位置。
6.切點:每一個類都擁有多個鏈接點,AOP經過切點定位到指定的鏈接點。例如:鏈接點至關於數據庫中的記錄(記錄有多條),切點至關於查詢條件,它能查詢到某一條記錄。開始調用切面的時候叫作切點,簡單的理解爲在哪裏開始調用日誌、事務的地方。this

相關文章
相關標籤/搜索