1. 程式人生 > >spring 的AOP和動態代理分析

spring 的AOP和動態代理分析

spring的AOP到底是什麼呢? 看看百度怎麼說

AOP(Aspect Oriented Programming 面向切面程式設計),通過預編譯方式和執行期動態代理實現程式功能的統一維護的一種技術。AOP是OOP的延續,是軟體開發中的一個熱點,也是Spring框架中的一個重要內容,是函數語言程式設計的一種衍生範型。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率。常用於日誌記錄,效能統計,安全控制,事務處理,異常處理等等

用自己的話來說,就是將一些與業務核心邏輯無關並且多個物件公用的程式碼塊封裝起來,然後供切入到程式碼中, 供它們使用

下面看看程式碼

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)

上面這個就是動態代理類(Proxy)類中的建立代理物件的方法,下面介紹一下方法的三個引數:

  • ClassLoader loader:方法需要動態生成一個類,這個類實現了A和B兩個介面,然後建立這個類的物件。需要生成一個類,而且這個類也需要載入到方法區中,所以我們需要一個ClassLoader來載入該類
  • Class<?>[] interfaces:我們需要代理物件的.Class物件的陣列
  • InvocationHandler h:呼叫處理器

InvocationHandler 這就是我們代理了這個介面之後,要進行的所有操作都在這裡面,這個類裡,我們可以重寫一個叫做invoke的方法,並且可以將要代理的實體物件傳入,在invoke裡可以進行邏輯方法新增還能呼叫傳入的例項物件的方法,這一步就相當於完成一個增強

package cn.et.utils;
 
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
 
public class MyInvocationHandler implements InvocationHandler{
	private Object targetObj;
	public MyInvocationHandler(Object targetObj){
		this.targetObj = targetObj;
	}
 
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("許可權驗證");
		Object resultObj = method.invoke(targetObj, args);
		System.out.println("日誌記錄");
		return resultObj;
	}
}

總結:使用動態代理的方法實現aop的步驟是,我們必須有一個介面,我們可以新建一個創造代理的類的類newProxyInstance,這個類中接受要被代理物件實現的介面,並且接受類載入器和一個執行器 InvocationHandler,通過這個執行器我們能接受那個實現介面的物件,在這個類裡可以重寫一個invoke方法,這個方法裡既能呼叫被代理物件的方法,還能使用 自己新增的類的方法,最後返回值就是代理物件的返回值

package cn.et.utils;
 
 
 
import java.lang.reflect.Proxy;
 
import org.junit.Test;
 
import cn.et.dao.UserDao;
import cn.et.dao.impl.StudentDao;
import cn.et.dao.impl.UserDaoImpl;
 
public class Checkout {
	@Test
	public void Testing(){
		UserDao userDao = new UserDaoImpl();
		/*
		Spring AOP(面向切面程式設計),擴充套件功能不修改原始碼實現,採用橫向抽取機制,取代了傳統縱向繼承體系重複性程式碼
		橫向抽取機制,底層使用動態代理方式實現
			針對有介面的情況時使用JDK中的java.lang.reflect類庫提供的動態代理
			針對沒有介面的情況時,使用Cglib框架提供的動態代理
		*/
		MyInvocationHandler handler = new MyInvocationHandler(userDao);
		UserDao proxyUserDao = (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(),userDao.getClass().getInterfaces(),handler);
		proxyUserDao.addUser();
		
		System.out.println("。。。。。。。。。。。。。");
		
		CglibProxy proxy = new CglibProxy();  
	    StudentDao proxyImp = (StudentDao)proxy.getProxy(StudentDao.class);  
	    proxyImp.addStudent();  
		
	}
}