深刻探索spring技術內幕(五): 剖析spring AOP工做原理

1、前言java

AOP (Aspect Oriented Programing) - 面向切面編程,它主要用於日誌記錄、性能分析、安全控制、事務處理、異常處理等方面。spring

AOP主要使用JDK的反射和動態代理,AOP代理實際上是由AOP框架動態生成的一個對象,該對象可做爲目標對象使用,AOP代理包含了目標對象的所有方法,但AOP代理的方法與目標對象的方法存在差別:AOP方法在特定切入點添加了加強處理,並回調了目標對象的方法。編程

 

動態代理的文章請參考:http://blog.csdn.net/zdp072/article/details/24868895安全

2、實現細節框架

下面這個例子利用AOP來實現日誌記錄:dom

附上一張類的結構圖,該例子須要導入dom4j.jar性能

①業務邏輯接口測試

/**
 * 業務邏輯類接口
 * @author zhangjim
 */
public interface BusinessService {
	/**
	 * 處理業務
	 */
	public void process();
}

② 業務邏輯實現this

/**
 * 業務邏輯對象實現類
 * @author zhangjim
 */
public class BusinessServiceImpl implements BusinessService {
	/**
	 * 處理業務
	 */
	public void process() {
		System.out.println("process business logic...");
	}
}

③ 通知類接口.net

/**
 * 通知類接口
 * @author zhangjim
 */
public interface Advisor {
	/**
	 * 所作的操做
	 */
	public void doInAdvisor(Object proxy, Method method, Object[] args);
}

④ 方法的前置通知

import java.lang.reflect.Method;

/**
 * 方法前置通知,它完成方法的前置操做
 * @author zhangjim
 */
public class BeforeMethodAdvisor implements Advisor {
	/**
	 * 在方法執行前所進行的操做
	 */
	public void doInAdvisor(Object proxy, Method method, Object[] args) {
		System.out.println("before process... ");
	}
}

⑤ 方法的後置通知

/**
 * 方法的後置通知,它完成方法的後置操做
 * @author zhangjim
 */
public class AfterMethodAdvisor implements Advisor {
	/**
	 * 在方法執行後所進行的操做
	 */
	public void doInAdvisor(Object proxy, Method method, Object[] args) {
		System.out.println("after process...");
	}
}

⑥ AOP處理器

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import com.zdp.advisor.Advisor;

/**
 * AOP處理器
 * @author zhangjim
 */
public class AopHandler implements InvocationHandler {
	private Object target; // 須要代理的目標對象
	Advisor beforeAdvisor; // 方法前置通知
	Advisor afterAdvisor; // 方法後置通知

	/**
	 * 設置代理目標對象,並生成動態代理對象.
	 * @param target 代理目標對象
	 * @return 返回動態代理對象
	 */
	public Object setObject(Object target) {
		this.target = target; // 設置代理目標對象 
		Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); // 根據代理目標對象生成動態代理對象
		return proxy;
	}

	/**
	 * 若定義了前置處理,則在方法執行前執行前置處理, 若定義了後置處理,則在方法調用後調用後置處理.
	 * 
	 * @param proxy 代理對象
	 * @param method 調用的業務方法
	 * @param args 方法的參數
	 * @return 返回結果信息
	 * @throws Throwable
	 */
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		if (beforeAdvisor != null) { 
			beforeAdvisor.doInAdvisor(proxy, method, args); // 進行業務方法的前置處理
		}
		method.invoke(target, args); // 執行業務方法
		if (afterAdvisor != null) {
			afterAdvisor.doInAdvisor(proxy, method, args); // 進行業務方法的後置處理
		}
		return null; // 返回結果對象
	}

	/**
	 * 設置方法的前置通知
	 * @param advisor 方法的前置通知
	 */
	public void setBeforeAdvisor(Advisor advisor) {
		this.beforeAdvisor = advisor;
	}

	/**
	 * 設置方法的後置通知
	 * @param advisor 方法的後置通知
	 */
	public void setAfterAdvisor(Advisor advisor) {
		this.afterAdvisor = advisor;
	}
}

⑦ Bean工廠類

import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import com.zdp.advisor.Advisor;

/**
 * Bean工廠類
 * @author zhangjim
 */
public class BeanFactory {
	private Map<String, Object> beansMap = new HashMap<String, Object>(); 

	/**
	 * Bean工廠的初始化
	 */
	public void init(String xml) {
		try {
			SAXReader reader = new SAXReader();
			ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
			InputStream ins = classLoader.getResourceAsStream(xml); // 讀取指定的配置文件
			Document doc = reader.read(ins);
			Element root = doc.getRootElement();
			AopHandler aopHandler = new AopHandler(); // 建立AOP處理器(動態生成的proxy類中持有了aopHandle的引用)
			for (Iterator iter = root.elementIterator("bean"); iter.hasNext();) { // 遍歷bean 
				Element element = (Element) iter.next(); 
				Attribute id = element.attribute("id"); // 獲取bean的屬性id、class、aopClass、aopType
				Attribute cls = element.attribute("class");
				Attribute aopClass = element.attribute("aopClass"); 
				Attribute aopType = element.attribute("aopType");
				
				if (aopClass != null && aopType != null) { // 若是配置了aopClass和aopType屬性時,需進行攔截操做
					Class advisorClass = Class.forName(aopClass.getText()); // 根據aopClass字符串獲取對應的類
					Advisor advisor = (Advisor) advisorClass.newInstance(); // 建立該類的對象 
					if ("before".equals(aopType.getText())) { // 根據aopType的類型來設置前置或後置顧問
						aopHandler.setBeforeAdvisor(advisor); 
					} else if ("after".equals(aopType.getText())) {
						aopHandler.setAfterAdvisor(advisor);
					}
				}

				Class clazz = Class.forName(cls.getText()); // 利用Java反射機制,經過class的名稱獲取Class對象 
				Object obj = clazz.newInstance(); // 建立一個對象 
				
				Object proxy = (Object) aopHandler.setObject(obj); // 產生代理對象proxy
				beansMap.put(id.getText(), proxy); // 將對象放入beansMap中,其中id爲key,對象爲value
			}
		} catch (Exception e) {
			System.out.println(e.toString());
		}
	}

	/**
	 * 經過bean的id獲取bean的對象.
	 * @param beanName bean的id
	 * @return 返回對應對象
	 */
	public Object getBean(String beanName) {
		Object obj = beansMap.get(beanName);
		return obj;
	}
}

⑧ 配置文件beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans>
	<bean id="businessService" class="com.zdp.service.BusinessServiceImpl" 
	aopClass="com.zdp.advisor.BeforeMethodAdvisor" aopType="before"></bean>
</beans>

⑨ 測試類

import com.zdp.service.BusinessService;
import com.zdp.spring.BeanFactory;
/**
 * 測試類
 * @author zhangjim
 */
public class Client {
	public static void main(String[] args) {
		BeanFactory beanFactory = new BeanFactory();  
		beanFactory.init("beans.xml");
		BusinessService proxy = (BusinessService) beanFactory.getBean("businessService");
		proxy.process();
	}
}

3、小結

上文僅僅是簡單地模擬了spring的AOP的實現,但仍是很好地展示了JDK反射和動態代理在spring中的應用,對於初學者理解AOP應該會有一點幫助。 

源碼下載地址: http://download.csdn.net/detail/zdp072/7284987

參考資料:http://www.ibm.com/developerworks/cn/java/j-lo-springaopcglib/

相關文章
相關標籤/搜索