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/