Spring實現AOP
1、什麼是 AOP
AOP (Aspect Orient Programming),直譯過來就是 面向切面程式設計。AOP 是一種程式設計思想,是物件導向程式設計(OOP)的一種補充。物件導向程式設計將程式抽象成各個層次的物件,而面向切面程式設計是將程式抽象成各個切面。
從該圖可以很形象地看出,所謂切面,相當於應用物件間的橫切點,我們可以將其單獨抽象為單獨的模組。
2、AOP的實現
【重要】:使用AOP需要匯入依賴包
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
</dependencies>
方式一:使用Spring的API介面【主要SpringAPI介面實現】
-
xml配置:
<!--註冊bean--> <bean id="userService" class="com.spong.demo03.UserServiceImpl"/> <bean id="logBefore" class="com.spong.demo03.LogBefore"/> <bean id="logAfter" class="com.spong.demo03.LogAfter"/> <!--方式一: 使用原生的Spring API介面--> <!--配置aop:需要匯入aop的約束--> <aop:config> 切入點:expression:表示式,execution(要執行的位置: * * * ...) <aop:pointcut id="pointcut" expression="execution(* com.spong.demo03.UserServiceImpl.*(..))"/> <!--執行環繞增加--> <aop:advisor advice-ref="logAfter" pointcut-ref="pointcut"/> <aop:advisor advice-ref="logBefore" pointcut-ref="pointcut"/> </aop:config>
-
需要切入的類(實現aop包下的介面MethodBeforeAdvice、AfterReturningAdvice等)
public class LogBefore implements MethodBeforeAdvice { /** * * @param method 要執行的目標物件的方法 * @param objects 方法引數 * @param o 目標物件 * @throws Throwable */ public void before(Method method, Object[] objects, Object o) throws Throwable { System.out.println(o.getClass().getName()+"的"+method.getName()+"執行"); } }
public class LogAfter implements AfterReturningAdvice { /** * * @param returnValue 方法執行後的返回值 * @param method * @param args * @param target * @throws Throwable */ public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println(target.getClass().getName()+"的"+method.getName()+"方法執行,返回值為"+returnValue); } }
方式二:自定義類來實現AOP【主要是切面定義】
-
自定義類:
public class Diy { public void logBefore(){ System.out.println("方法執行前"); } public void logAfter(){ System.out.println("方法執行後"); } }
-
xml配置:
<!--方式二: 自定義類--> <bean id="diy" class="com.spong.demo03.Diy"/> <aop:config> <aop:aspect ref="diy"> <aop:pointcut id="pointcut" expression="execution(* com.spong.demo03.UserServiceImpl.*(..))"/> <aop:before method="logBefore" pointcut-ref="pointcut"/> <aop:after method="logAfter" pointcut-ref="pointcut"/> </aop:aspect> </aop:config>
方式三:使用註解實現
-
使用註解實現的切面類:
//使用註解實現AOP @Aspect //標註為一個切面 @Component //注入bean public class AnnotationPointCut { //設定切入點 @Pointcut("execution(* com.spong.demo03.UserServiceImpl.*(..))") private void pointCut(){} @Before("pointCut()") public void logBefore(){ System.out.println("方法執行前"); } @After("pointCut()") public void logAfter(){ System.out.println("方法執行後"); } @Around("pointCut()") //環繞增強,我們可以給定一個引數,代表我們要獲取處理切入的點; public void around(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("環繞前"); System.out.println(joinPoint.getSignature()); //獲得簽名(呼叫了哪個類的哪個方法) Object proceed = joinPoint.proceed(); System.out.println("環繞後"); } }
-
xml配置:
<!--開啟aop註解支援--> <aop:aspectj-autoproxy/> <!--開啟註解支援--> <context:component-scan base-package="com.spong.demo03"/> <context:annotation-config></context:annotation-config>
-
測試類
public class MyTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //這裡返回的是一個代理類例項,代理類也是實現了UserService介面 UserService userService = context.getBean("userService", UserService.class); userService.add(); } }
-
測試結果:
環繞前 void com.spong.demo03.UserService.add() 方法執行前 add 方法執行後 環繞後
切入點表示式execution (* com.sample.service..*. *(..))解析:
整個表示式可以分為五個部分:
1、execution()::表示式主體。
2、第一個*號:表示返回型別, *號表示所有的型別。
3、包名:表示需要攔截的包名,後面的兩個句點表示當前包和當前包的所有子包,com.sample.service包、子孫包下所有類的方法。
4、第二個號:表示類名,號表示所有的類。
5、(..):最後這個星號表示方法名,號表示所有的方法,後面括弧裡面表示方法的引數,兩個句點表示任何引數