1. 程式人生 > >Spring進階之路(10)-Advice簡介以及通過cglib生成AOP代理物件

Spring進階之路(10)-Advice簡介以及通過cglib生成AOP代理物件

Advice簡介

1. Before:在目標方法執行之前執行織入,如果Before的處理中沒有進行特殊的處理,那麼目標方法最終會執行,但是如果想要阻止目標方法執行時,可以通過丟擲一個異常來實現,Before處理無法拿到目標方法的返回值,因為這時候目標方法並未執行。

2. AfterReturning: 返回之後執行(前提是目標方法執行成功),可以訪問到目標物件的返回值,但是不可以改變返回值。

3. AfterThrowing:丟擲異常之後執行,可以對異常進行適當的修復或者將異常輸出到日誌中。

4. After:不管目標物件執行成功與否都會被織入常用於釋放資源等。

5. Around:既可以在目標方法之前,又可以在目標方法呼叫之後執行,但是需要線上程安全的情況下執行,如果需要目標方法執行之前或者之後共享某種資料,應該考慮用Around。需要改變返回值的時候,只能使用Around。

通過cglib生成AOP代理物件

上一篇文章中已經提到,通過JDK的代理生成AOP代理物件的方式,但是前提是目標方法實現了介面,如果沒有實現介面的話,那麼怎麼辦?

在這種情況下,我們使用cglib來實現生成AOP代理物件。

定義一個沒有實現介面的User類。

package com.siti.spring20160315;

public class User {

	private String userName;
	private String password;
	
	public User(){}
	
	public User(String userName, String password) {
		super();
		this.userName = userName;
		this.password = password;
	}
	
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}

	public void saySth() {
		System.out.println("hello!");
	}
}
對於Spring而言,如果說目標類實現了介面的話,會按照JDK代理生成AOP代理物件,如果沒有實現介面的話,那麼會使用cglib來生成AOP代理物件。
package com.siti.spring20160315;

import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.InvocationHandler;


public class MyProxy4AOPObject implements InvocationHandler{

	private Object targetObj;
	
	public Object getProxyObject(Object targetObj){
		this.targetObj = targetObj;
		
		Enhancer enhance = new Enhancer();
		// 將目標類設定為代理物件的父類,產生目標類的子類,這個子類覆蓋所有父類的非final修飾的方法
		enhance.setSuperclass(this.targetObj.getClass());
		// 設定回撥,可以單獨建立一個類實現InvocationHandler介面實現裡面的invoke方法
		enhance.setCallback(this);
		
		return enhance.create();
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		
		User user = (User)this.targetObj;
		Object result = null;
		try{
			// 攔截,符合要求的才允許執行
			if(user.getUserName() != null && user.getUserName() != ""){
				// -->Before
				result = method.invoke(this.targetObj, args);
				// -->AfterReturning
			}
		}catch (Exception e) {
			// -->AfterThrowing
		}finally{
			// -->After
		}
		
		return result;
	}

}

package com.siti.spring20160315;

public class MainTest {

	public static void main(String[] args) {
		User user = new User("wy", "wy");
		MyProxy4AOPObject myProxy4AOPObject = new MyProxy4AOPObject();
		User us = (User) myProxy4AOPObject.getProxyObject(user);
		us.saySth();
	}
}
這裡會輸出:hello!

如果將User中name屬性賦值為null或者""的話就不會輸出,因為在invoke方法中進行了限制,呼叫的目標物件的方法不會執行。