前面已經學過了bean的相關知識,對bean的配置方法也有了一定的瞭解。下面來學習Spring中一個重要的知識點AOP編程,這些知識點都是根據韓順平老師的視頻總結而來,雖然簡單,但是作爲入門瞭解還是不錯的。不過想要真正的應用到項目中,還需要進行深一步的學習。
- AOP的概念
AOP(aspect oriented programming)面向切面編程,是對所有對象或是一類對象編程,核心是在不增加代碼的基礎上,還能增加功能。他所應用到的場景一般是將交叉功能(事務、日誌)提取出來。
2、AOP術語
1、切面:要實現的交叉功能,是系統模塊化的一個切面或者領域(如日誌記錄等)
2、連接點:應用程序執行過程中插入切面的地點,可以是方法調用,異常拋出,或者要修改的字段。
3、通知:切面的實際實現,他通知系統新的行爲。如在日誌通知包含了實現日誌功能的代碼,向日志文件寫日誌。通知在連接點插入到應用系統中。
4、切入點:定義了通知應該應用在哪些連接點,通知可以應用到AOP框架支持的任何連接點。
5、引入:爲類添加新的方法和屬性
6、目標對象:被通知的對象,既可以是你編寫的類,也可以是第三方的類
7、代理:將通知應用到目標對象後創建的對象,應用系統的其他部分不用爲了支持代理對象而改變
8、織入:將切面應用到目標對象從而創建一個新的代理對象的過程。織入發生在目標對象生命週期的多個點上
編譯器:切面在目標對象編譯時織入,這需要一個特殊的編譯器
類裝載器:切面在目標對象那個被載入JVM是織入,這需要一個特殊的類載入器
運行期:切面在應用系統運行時織入
3、配置步驟
步驟:
1、定義接口
2、編寫對象(被代理對象=目標對象)
3、編寫通知
4、bean.xml文件配置
1、配置被代理對象
2、配置通知
3、配置代理對象(是proxyFactoryBean實例)
a、配置被代理對象
b、配置代理接口集
c、把通知織入代理對象
下面我們來舉個例子,需求就是在調用UserBean 的sayHello()前利用前置通知完成日誌的書寫,利用環繞通知將sayHello方法包裹起來(然而現在並不能瞭解環繞通知的具體應用場景是什麼),調用完sayHello方法後,最後用後置通知釋放資源。
首先來看一下框架圖:
- 定義接口:
package rogue.aop; public interface TestSeverInter { public void sayHello(); } package rogue.aop; public interface TestSeverInter2 { public void sayBye(); }
2.編寫目標對象
package rogue.aop; public class SeverTest1 implements TestSeverInter,TestSeverInter2 { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public void sayHello() { System.out.println("Hello"+name); } @Override public void sayBye() { System.out.println("Bye"+name); } }
3、編寫通知.package rogue.aop; import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; public class MyMethodBeforeAdvice implements MethodBeforeAdvice { @Override /** * method:被調用的方法的名字 * args:傳遞的參數 * target:目標對象(就是被調用的對象) * */ public void before(Method method, Object[] args, Object target) throws Throwable { // TODO Auto-generated method stub System.out.println("前置通知-通知日誌..."+method.getName()); } }
package rogue.aop; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; public class MyMethodSurroundAdvice implements MethodInterceptor { @Override public Object invoke(MethodInvocation arg0) throws Throwable { // TODO Auto-generated method stub System.out.println("調用環繞通知前。。"); arg0.proceed(); System.out.println("調用環繞通知後。。"); return null; } }
package rogue.aop; import java.lang.reflect.Method; import org.springframework.aop.AfterReturningAdvice; public class MyMethodAfterAdvice implements AfterReturningAdvice { @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { // TODO Auto-generated method stub System.out.println("關閉資源。。。"); } }
4、bean.xml的配置<?xml version="1.0" encoding="utf-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <!-- 配置被代理對象 --> <bean id="SeverTest1" class="rogue.aop.SeverTest1"> <property name="name" value="大帽子" /> </bean> <!--配置通知--> <!-- 配置前置通知 --> <bean id="MyMethodBeforeAdvice" class="rogue.aop.MyMethodBeforeAdvice" /> <!-- 配置後置通知 --> <bean id="MyMethodAfterAdvice" class="rogue.aop.MyMethodAfterAdvice" /> <!-- 配置環繞通知 --> <bean id="MyMethodSurroundAdvice" class="rogue.aop.MyMethodSurroundAdvice" /> <!-- 配置代理對象(也就是將被代理對象,接口和通知整合起來,配置在一起) --> <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 第一步:將被代理對象織入到代理對象中 (name一定要是target)--> <property name="target" ref="SeverTest1"></property> <!-- 第二步:將代理接口集織入到代理對象中 (name一定要是proxyInterfaces)--> <property name="proxyInterfaces"> <list> <value>rogue.aop.TestSeverInter</value><!-- 這裏應該是全限定名 --> <value>rogue.aop.TestSeverInter2</value> </list> </property> <!-- 第三步:把通知織入到代理對象(name一定要是interceptorNames) --> <property name="interceptorNames"> <list> <!-- 相當於把MyMethodBeforeAdvice前置通知和代理對象關聯,也可以把通知看作攔截器 --> <value>MyMethodBeforeAdvice</value> <value>MyMethodAfterAdvice</value> <value>MyMethodSurroundAdvice</value> </list> </property> </bean> </beans>
測試程序package rogue.aop; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class app { /** * @param args */ public static void main(String[] args) { ApplicationContext aContext = new ClassPathXmlApplicationContext("rogue/aop/aop.xml"); //在這裏我們應該取proxyFactoryBean,因爲在這裏面有我們織入的通知,執行完通知後再執行正常的代碼 TestSeverInter tS = (TestSeverInter) aContext.getBean("proxyFactoryBean"); tS.sayHello(); System.out.println("**********************************"); ((TestSeverInter2)tS).sayBye(); } }
結果截圖: