首先。AOP 面向切面編程。
就是說通過配置將業務邏輯和系統的服務分離。目的是讓業務邏輯之關系業務的處理而不再去處理其他事情。其中切面一般都是哪些可以為多個類提供服務的模塊,將其封裝起來稱為切面。減少系統的重復代碼和低模塊之間的耦合度。一般用于權限驗證、日志、事務等。
攔截器也是應用了AOP的思想,將攔截(請求)Action以進行一些預處理或者結果處理。Spring的AOP可以攔截Spring管理的bean。
AOP主要是通過動態代理和反射機制實現的。
Spring代理實際上是對JDK代理和CGLIB代理做了一層封裝,并且引入了AOP概念:Aspect、advice、joinpoint等等,同時引入了AspectJ中的一些注解@pointCut,@after,@before等等.Spring Aop嚴格的來說都是動態代理,所以實際上Spring代理和Aspectj的關系并不大.
基礎概念
通知(Advice) 定義了切入點代碼執行時間點附近需要做的工作。
切入點: @Before org.apringframework.aop.MethodBeforeAdvice @After-returning(返回后) org.springframework.aop.AfterReturningAdvice @After-throwing(拋出后) org.springframework.aop.ThrowsAdvice @Arround周圍 org.aopaliance.intercept.MethodInterceptor @Introduction引入 org.springframework.aop.IntroductionInterceptor 2. 連接點(Joinpoint) 程序能夠應用通知 的一個時機。這些時機就是連接點。比如方法調用時、異常拋出時、方法返回后等。 3. 切入點(Pointcut) 通知定義了切面要發生的故事,連接點定義了故事要發生的時機,而切入點定義了故事發生的地點,例如某個類or方法的名稱。Spring中允許我們用正則表達式來指定。
切面(Aspect) Advice Joinpoint Pointcut共同組成了切面:要發生的故事、時間、地點引入(Introduction) 引入允許我們向現有的類添加新的方法和屬性。 Spring中的方法注入的功能。目標(Target) 就是被通知的對象。 如果沒有AOP,通知的邏輯就要寫在目標對象中。有了AOP之后他可以只關注自己要做的事情,解耦。代理(Proxy) 應用通知的對象。織入(Weaving) 把切面應用到目標對象來創建新的代理對象的過程。 織入一般發生在以下幾個時機: 一 編譯時 :AspectJ的織入編譯器 二 類加載時 :使用特殊的ClassLoader在目標類被加載到程序之前增強類的字節代碼。 三 運行時 :切面在運行的某一個時刻被織入,SpringAOP就是運行時織入切面的。(JDK的動態代理技術)
使用AOP的幾種方式:
經典的基于代理的AOP @AspectJ注解驅動的切面 純POJO切面 注入式AspectJ切面
舉一個例子: Me類是實現了Sleepable的接口,重寫了其中的sleep方法。
基于代理的AOP
由于Me完成了sleep的邏輯,但是其他睡覺需要的功能 ,例如起床穿衣服,睡前脫衣服都可以由AOP代替“Me”執行。實現解耦。 那么我們就可以通過SleepHelper類
public class SleepHelper implements MethodBeforeAdvice, AfterReturningAdvice { public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable { System.out.println("睡覺前要脫衣服!"); } public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable { System.out.println("起床后要穿衣服!"); } }
Spring配置文件 application.xml配置AOP
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
<span style="white-space:pre"> </span>xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<span style="white-space:pre"> </span>xmlns:aop="http://www.springframework.org/schema/aop"
<span style="white-space:pre"> </span>xsi:schemaLocation="http://www.springframework.org/schema/beans
<span style="white-space:pre"> </span>http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
<span style="white-space:pre"> </span>http://www.springframework.org/schema/aop
<span style="white-space:pre"> </span>http://www.springframework.org/schema/aop/spring-aop-3.0.xsd "> <!-- 定義被代理者 --> <bean id="me" class="com.springAOP.bean.Me"></bean> <!-- 定義通知內容,也就是切入點執行前后需要做的事情 --> <bean id="sleepHelper" class="com.springAOP.bean.SleepHelper"></bean> <!-- 定義切入點位置 --> <bean id="sleepPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut"> <property name="pattern" value=".*sleep"></property> </bean> <!-- 使切入點與通知相關聯,完成切面配置 --> <bean id="sleepHelperAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"> <property name="advice" ref="sleepHelper"></property> <property name="pointcut" ref="sleepPointcut"></property> </bean> <!-- 設置代理 --> <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 代理的對象,有睡覺能力 --> <property name="target" ref="me"></property> <!-- 使用切面 --> <property name="interceptorNames" value="sleepHelperAdvisor"></property> <!-- 代理接口,睡覺接口 --> <property name="proxyInterfaces" value="com.springAOP.bean.Sleepable"></property> </bean> </beans>
其中配置標簽中的幾個重要屬性
xmlns:是默認的xml文檔解析格式,即spring的beans。地址是http://www.springframework.org/schema/beans;通過設置這個屬性,所有在beans里面聲明的屬性,可以直接通過<>來使用,比如<bean>等等。一個XML文件,只能聲明一個默認的語義解析的規范。例如上面的xml中就只有beans一個是默認的,其他的都需要通過特定的標簽來使用,比如aop,它自己有很多的屬性,如果要使用,前面就必須加上aop:xxx才可以。類似的,如果默認的xmlns配置的是aop相關的語義解析規范,那么在xml中就可以直接寫config這種標簽了。xmlns:xsi:是xml需要遵守的規范,通過URL可以看到,是w3的統一規范,后面通過xsi:schemaLocation來定位所有的解析文件。xmlns:aop:這個是重點,是我們這里需要使用到的一些語義規范,與面向切面AOP相關。xmlns:tx:Spring中與事務相關的配置內容。
測試:通過AOP代理的方式執行Me的sleep()方法,會把執行前、執行后的操作執行,實現了AOP的效果!
public class Test { public static void main(String[] args){ @SuppressWarnings("resource") //如果是web項目,則使用注釋的代碼加載配置文件,這里是一般的Java項目,所以使用下面的方式 //ApplicationContext appCtx = new ClassPathXmlApplicationContext("application.xml"); ApplicationContext appCtx = new FileSystemXmlApplicationContext("application.xml"); Sleepable me = (Sleepable)appCtx.getBean("proxy"); me.sleep(); }
}
然后我們其實可以通org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator簡化配置。
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
在Test中就可以直接獲取me對象,執行sleep方法。自動匹配,切面會自動匹配符合切入點的bean,會被自動代理,實現功能。
AspectJ提供的注解實現AOP
AspactJ框架常用注解: @PonitCut // 聲明切入點的注解 @Before // 聲明前置通知注解 @After // 聲明后置通知注解(原始方法執行正常或者非正常執行都會進入) @AfterReturing //聲明后置通知注解(原始方法必須正常執行) @AfterThrowing // 聲明異常通知 @Around // 環繞通知注解
修改SleepHelper類
@Aspect
public class SleepHelper{ public SleepHelper(){ } @Pointcut("execution(* *.sleep())") public void sleeppoint(){} @Before("sleeppoint()") public void beforeSleep(){ System.out.println("睡覺前要脫衣服!"); } @AfterReturning("sleeppoint()") public void afterSleep(){ System.out.println("睡醒了要穿衣服!"); } }
在方法中,可以加上JoinPoint參數以進行相關操作,如:
//當拋出異常時被調用 public void doThrowing(JoinPoint point, Throwable ex) { System.out.println(“doThrowing::method " + point.getTarget().getClass().getName() + “.” + point.getSignature().getName() + " throw exception”); System.out.println(ex.getMessage()); }
然后修改配置為:
<aop:aspectj-autoproxy />
<!-- 定義通知內容,也就是切入點執行前后需要做的事情 -->
<bean id="sleepHelper" class="com.springAOP.bean.SleepHelper"></bean>
<!-- 定義被代理者 -->
<bean id="me" class="com.springAOP.bean.Me"></bean>
測試
public class Test { public static void main(String[] args){ @SuppressWarnings(“resource”) //如果是web項目,則使用注釋的代碼加載配置文件,這里是一般的Java項目,所以使用下面的方式 //ApplicationContext appCtx = new ClassPathXmlApplicationContext(“application.xml”); ApplicationContext appCtx = new FileSystemXmlApplicationContext(“application.xml”); Sleepable me = (Sleepable)appCtx.getBean(“me”); me.sleep(); } }
Pojo切面
使用Spring來定義純粹的POJO切面 (名字很繞口,其實就是純粹通過aop:fonfig標簽配置,也是一種比較簡單的方式)。
修改SleepHelper類,所以這種方式的優點就是在代碼中不體現任何AOP相關配置,純粹使用xml配置 。
public class SleepHelper{
public void beforeSleep(){ System.out.println("睡覺前要脫衣服!"); } public void afterSleep(){ System.out.println("睡醒了要穿衣服!"); }
}
配置文件
<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd "> <!-- 定義通知內容,也就是切入點執行前后需要做的事情 --> <bean id="sleepHelper" class="com.springAOP.bean.SleepHelper"></bean> <!-- 定義被代理者 --> <bean id="me" class="com.springAOP.bean.Me"></bean> <aop:config> <aop:aspect ref="sleepHelper"> <aop:before method="beforeSleep" pointcut="execution(* *.sleep(..))" /> <aop:after method="afterSleep" pointcut="execution(* *.sleep(..))" /> </aop:aspect> </aop:config> </beans>
另一種配置寫法
<aop:config> <aop:aspect ref="sleepHelper"> <aop:pointcut id="sleepHelpers" expression="execution(* *.sleep(..))" /> <aop:before pointcut-ref="sleepHelpers" method="beforeSleep" /> <aop:after pointcut-ref="sleepHelpers" method="afterSleep" /> </aop:aspect>
</aop:config>
轉自:https://blog.csdn.net/summer_yuxia/article/details/75104949
總結
以上是生活随笔 為你收集整理的SpringAOP基础以及四种实现方式 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。