在Spring中默認使用JDK動態代理實現AOP編程,使用org.springframework.aop.framework.ProxyFactoryBean建立代理是Spring AOP 實現的最基本方式。java
根據Spring中通知在目標類方法中的鏈接點位置,通知能夠分爲6種類型:正則表達式
(1)環繞通知spring
環繞通知(org.aopalliance.intercept.MethodInterceptor)是在目標方法執行前和執行後實施加強,可應用於日誌記錄、事務處理等功能。編程
(2)前置通知app
前置通知(org.springframework.aop.MethodBeforeAdvice)是在目標方法執行前實施加強,可應用於權限管理等功能。ide
(3)後置返回通知測試
後置返回通知(org.springframework.aop.AfterReturningAdvice)是在目標方法成功執行後實施加強,可應用於關閉流、刪除臨時文件等功能。spa
(4)後置(最終)通知代理
後置通知(org.springframework.aop.AfterAdvice)是在目標方法執行後實施加強,與後置返回通知不一樣的是,無論是否發生異常都要執行該類通知,該類通知可應用於釋放資源。日誌
(5)異常通知
異常通知(org.springframework.aop.ThrowsAdvice)是在方法拋出異常後實施加強,可應用於處理異常、記錄日誌等功能。
(6)引入通知
引入通知(org.springframework.aop.IntroductionInterceptor)是在目標類中添加一些新的方法和屬性,可應用於修改目標類(加強類)。Spring AOP 只支持方法層面的加強,因此該類型的通知只做爲了解便可。
ProxyFactoryBean是org.springframework.beans.factory.FactoryBean 接口的實現類,FactoryBean負責實例化一個Bean實例,ProxyFactoryBean負責爲其餘Bean實例建立代理實例。ProxyFactoryBean類的經常使用屬性以下:
在pom.xml中導入AOP聯盟和Spring-aop的相關依賴
<!-- AOP聯盟依賴 --> <dependency> <groupId>aopalliance</groupId> <artifactId>aopalliance</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.0.2.RELEASE</version> </dependency>
建立StuDao接口和StuDaoImpl實現類,示例代碼以下:
StuDao接口
public interface StuDao { public void save(); public void modify(); public void delete(); }
StuDaoImpl實現類
public class StuDaoImpl implements StuDao { @Override public void save() { System.out.println("保存"); } @Override public void modify() { System.out.println("修改"); } @Override public void delete() { System.out.println("刪除"); } }
建立切面類MyBeforeAdvice,僅實現前置通知
import org.springframework.aop.MethodBeforeAdvice; import java.lang.reflect.Method; public class MyBeforeAdvice implements MethodBeforeAdvice { @Override public void before(Method method, Object[] objects, Object o) throws Throwable { System.out.println("前置加強========"); } }
在applicationContext.xml中配置切面並指定代理
<!--配置目標類--> <bean id="stuDao" class="aop.StuDaoImpl"></bean> <!--配置前置通知類型--> <bean id="myBeforeAdvice" class="aop.MyBeforeAdvice"></bean> <!--Spring AOP 生成代理對象--> <bean id="stuDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <!--配置目標類--> <property name="target" ref="stuDao"></property> <!--代理實現的接口--> <property name="proxyInterfaces" value="aop.StuDao"></property> <!--採起攔截的名稱--> <property name="interceptorNames" value="myBeforeAdvice"></property> </bean>
建立測試類
@Test public void demo(){ ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml"); StuDao stuDao = (StuDao) app.getBean("stuDaoProxy"); stuDao.save(); stuDao.modify(); stuDao.delete(); }
運行結果
使用普通Advice做爲切面,將對目標類全部方法進行攔截,不夠靈活,在實際開發中常採用帶切點的切面。
經常使用PointcutAdvisor實現類:
建立StuDao接口和StuDaoImpl實現類,示例代碼以下:
StuDao接口
public interface StuDao { public void save(); public void modify(); public void delete(); }
StuDaoImpl實現類
public class StuDaoImpl implements StuDao { @Override public void save() { System.out.println("保存"); } @Override public void modify() { System.out.println("修改"); } @Override public void delete() { System.out.println("刪除"); } }
下面建立一個實現環繞通知的切面類
import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; public class MyAspect implements MethodInterceptor { @Override public Object invoke(MethodInvocation m) throws Throwable { //前置加強方法 check(); //執行目標方法 Object obj = m.proceed(); //後置加強方法 log(); return obj; } public void check(){ System.out.println("模擬權限控制"); } public void log(){ System.out.println("模擬日誌記錄"); } }
在applicationContext.xml中配置切面並指定代理
<!--配置目標類--> <bean id="stuDao" class="aop.StuDaoImpl"></bean> <!--配置通知--> <bean id="myAspect" class="aop.MyAspect"></bean> <!--配置帶切入點的切面--> <bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <!--pattern中配置正則表達式:.表示任意字符 *表示任意次數--> <property name="pattern" value=".*"></property> <property name="advice" ref="myAspect"></property> </bean> <!--Spring AOP 生成代理對象--> <bean id="stuDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <!--配置目標類--> <property name="target" ref="stuDao"></property> <!--代理實現的接口--> <property name="proxyInterfaces" value="aop.StuDao"></property> <!--採起攔截的名稱--> <property name="interceptorNames" value="myAdvisor"></property> </bean>
建立測試類
@Test public void demo(){ ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml"); StuDao stuDao = (StuDao) app.getBean("stuDaoProxy"); stuDao.save(); stuDao.modify(); stuDao.delete(); }
運行結果