Spring AOP梳理
阿新 • • 發佈:2017-10-23
xml配置 調用 beans spec 必須 源碼 什麽 config color
一、Srping AOP
AOP(Aspect Oriented Programming)解釋為面向切面編程,何為切面,用刀把一塊面包切成兩半,刀切下去形成的面就叫切面,那麽面向切面的就是形成切面的這把刀,刀切在哪(切入點),怎麽切(通知),切成什麽樣(通知實現方法),切的過程就是切面織入的過程。這種編程方式主要為了分離關註點並且能夠增強類的輔助功能。比如做日誌管理,權限控制等工作,在特定的時候和位置做特定的事情,而無需在原來方法中做特殊處理。
AOP概念:
-
-
- 切面:多個對象或方法要實現的交叉功能的集合。
- 連接點:被關註的方法,執行了該方法會觸發通知。
- 切入點:一系列連接點的集合。
- 通知:切面的實際實現,在連接點方法被執行的時候在適當的地方插入通知。
- before:前置通知,在方法被調用之前調用
- after:後置通知,在方法執行結束之後調用,無論方法是否執行成功
- around:環繞通知,在目標方法執行前和執行結束之後分別執行自定義方法
- after-return:在方法成功執行之後調用,
- after-throwing:在方法拋出異常後調用
- 目標對象:被通知的對象,可以是自己的編寫的類也可以是,第三方類對象。(連接點就是目標對象中的某些方法)
- 代理:將通知應用到目標對象後創建的對象。
- 織入:將切面應用到目標對象從而創建一個新的代理對象的過程。
- 引入:為類添加新的方法和屬性。(<aop:declare-parents ../>)
- 切面:多個對象或方法要實現的交叉功能的集合。
-
二、AOP配置範例:
1.spring中的aop的xml配置方式簡單實例
2.spring中aop的註解實現方式簡單實例
3.利用切面為特定的類添加新功能:
<aop:config> <!-- 兩個切面--> <aop:aspect ref="company"> <!-- 利用切面為特定的類添加新功能 --> <aop:declare-parents types-matching="com.springAop.InstanceMine+" <!-- 實現了InstanceMine接口的實現類可以強轉成InstanceOtheer類型的對象並使用他的實現類的方法的方法 -->
implement-interface="com.springAop.InstanceOther" default-impl="com.springAop.OtherImpl"/> <!--InstanceOther的默認實現類,當InstanceMine對象強轉成InstanceOther的對象時,默認實現類為OtherImpl--> </aop:aspect> </aop:config>
接口類:instanceMine和instanceOther
public interface InstanceMine { public void speak1(String meg); } public interface InstanceOther { public void speak2(String meg); }
接口實現類: OtherImple和MineImpl
public class MineImpl implements instanceMine { public void speak1(String meg) { System.out.println("s1"); } } public class OtherImpl implements instanceOther { public void speak2(String meg) { System.out.println(meg); } }
測試類:Test
public class Test { @org.junit.jupiter.api.Test public void TestDemo(){ ApplicationContext app = new FileSystemXmlApplicationContext("src/main/java/com/springAop/bean.xml"); InstanceMine mine = app.getBean("mine",instanceMine.class); ((InstanceOther)mine).speak2("我可以說話嗎");//強轉成InstanceOther,並調用實現類OtherImpl的實現方法 } }
結果:
三.以代理對象的方式實現AOP:
1.前置通知:
1 /** 2 * 前置通知:實現MethodBeforeAdvice接口,在目標方法執行之前執行 3 * 相當於aop配置<aop:before method="before" pointcut-ref="當前類的bean"/> 4 */ 5 public class BeforeNotify implements MethodBeforeAdvice { 6 7 public void before(Method method, Object[] objects, Object o) throws Throwable { 8 System.out.println("=========== 前置通知 ========="); 9 } 10 }
2.後置通知:
1 /** 2 * 後置(返回)通知:在方法結束返回時調用,一般包含在環繞通知結束前執行, 3 * 方法成功執行有效,異常結束則該方法無效。 4 * 相當於aop配置:<aop:after-returning method="afterReturning" pointcut-ref="當前類的bean"/> 5 */ 6 public class AfterNotify implements AfterReturningAdvice { 7 public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { 8 System.out.println("=========== 後置通知 ========="); 9 } 10 }
3.環繞通知:
1 /** 2 * 環繞通知:在方法執行前和執行後均可以執行自定義的方法, 3 * 相當於aop配置:<aop:around method="invoke" pointcut-ref="當前類的Bean"/> 4 */ 5 public class AroundNotify implements MethodInterceptor { 6 7 public Object invoke(MethodInvocation methodInvocation) throws Throwable { 8 System.out.println("=========== 環繞通知 ========="); 9 Object obj = methodInvocation.proceed();//執行目標方法 10 System.out.println("=========== 環繞通知 ========="); 11 return obj; 12 } 13 }
4.異常通知:
1 /** 2 * 異常通知:在目標方法執行異常時執行, 3 * 註意:ThrowsAdvice是個空接口,裏面未定義任何待實現類 4 * 相當於aop配置:<aop:after-throwing method="afterThrowing" pointcut-ref="當前類的bean"/> 5 */ 6 public class ExceptionNotify implements ThrowsAdvice { 7 public void afterThrowing(Method method, Object[] args, Object target, Exception ex){ 8 System.out.println("方法:"+method.getName()+"出錯了\n原因:"+ex.getMessage()); 9 } 10 }
此處的ThrowAdvice接口是沒有實現方法的,但是又不允許隨便定義,在源碼中我們看到了規定的幾個方法,因為此接口中,沒有任何實現方法,當被利用反射機制調用的時候,必須實現一下方法中的一種,這是源碼註釋的說明:
5.bean配置
1 <beans xmlns="http://www.springframework.org/schema/beans" 2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> 4 5 <!-- 被代理對象 --> 6 <bean class="com.springAop.proxyAOP.UserDao" id="userDao"/> 7 8 <!-- 關聯通知 --> 9 <bean class="com.springAop.proxyAOP.BeforeNotify" id="before"/> 10 <bean class="com.springAop.proxyAOP.AroundNotify" id="aroundNotify"/> 11 <bean class="com.springAop.proxyAOP.ExceptionNotify" id="exceptionNotify"/> 12 <bean class="com.springAop.proxyAOP.AfterNotify" id="afterNotify"/> 13 14 <!-- 代理對象 --> 15 <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean"> 16 <!-- 代理對象接口,接口方法就是連接點 --> 17 <property name="proxyInterfaces"> 18 <list> 19 <!-- 目標對象實現的接口類,實現了那些接口都可以補充進去,接口的方法就是一個個連接點 --> 20 <value>com.springAop.proxyAOP.IUserDao</value> 21 <value>com.springAop.proxyAOP.BookDao</value> 22 </list> 23 </property> 24 25 <!-- 關聯通知類型 --> 26 <property name="interceptorNames"> 27 <list> 28 <value>before</value><!-- 前置通知織入 --> 29 <value>aroundNotify</value><!-- 環繞通知織入 --> 30 <value>exceptionNotify</value><!-- 異常通知織入 --> 31 <value>afterNotify</value><!-- 後置通知織入 --> 32 </list> 33 </property> 34 35 <!-- 關聯被代理對象(aop的目標對象) --> 36 <property name="target" ref="userDao"/> 37 </bean> 38 </beans>
6.目標對象:(實現了兩個接口)
1 public class UserDao implements IUserDao,BookDao{ 2 public void save() { 3 System.out.println("保存用戶信息中。。。。"); 4 // int i=1/0; 5 } 6 7 public void getBook() { 8 System.out.println("拿到一本書"); 9 } 10 }
7.測試類:
1 public class Test{ 2 @org.junit.jupiter.api.Test 3 public void testDemo(){ 4 ApplicationContext app = new FileSystemXmlApplicationContext("file:G:\\DevelopSoftware\\IDEA\\workspace\\springDemo\\src\\main\\java\\com\\springAop\\proxyAOP\\bean.xml"); 5 /** 6 * 獲取的bean是目標對象的代理對象,可以將代理對象強轉成任何目標對象實現的接口對象 7 */ 8 IUserDao userDao = app.getBean("proxyFactoryBean",IUserDao.class); 9 userDao.save(); 10 System.out.println("========================="); 11 /** 12 * 將代理對象強轉成BookDao接口對象,並調用該接口方法。 13 */ 14 ((BookDao)userDao).getBook(); 15 } 16 }
運行結果:
Spring AOP梳理