前置通知
【Spring AOP】
1.AspectJ:Java社區裏最完整最流行的AOP框架。
2.在Spring2.0 以上的版本中,可以使用基於AspectJ註解或基於XML配置的AOP。
【在Spring中啟用AspectJ註解支持】
1.要在Spring應用中使用AspectJ註解,必須在classpath下包含AspectJ類庫:aopalliance.jar、aspectj.weaver.jar和spring-aspects.jar。
2.將aop Schema添加到<beans>根元素中。
3.要在Spring IOC容器中啟用AspectJ註解支持,只要在Bean配置文件中定義一個空的XML元素<aop:aspectj-autoproxy>。
4.當Spring IOC容器偵測到Bean配置文件中的<aop:aspectj-autoproxy>元素時,會自動為與AspectJ切面匹配的Bean創建代理。
【用AspectJ註解聲明切面】
1.要在Spring中聲明AspectJ切面,只需要在IOC容器中將切面聲明為Bean實例。當在Spring IOC容器中初始化AspectJ切面之後,Spring IOC 容器就會為那些與AspectJ切面相匹配的Bean創建代理。
2.在AspectJ註解中,切面只是一個帶有@Aspect註解的Java類。
3.通知是標註有某種註解的簡單的Java方法。
4.AspectJ支持5種類型的通知註解:
--@Before:前置通知,在方法執行之前執行
--@After:後置通知,在方法執行之後執行
--@AfterRunning:返回通知,在方法返回結果之後執行
--@AfterThrowing:異常通知,在方法拋出異常之後
--@Around:環繞通知,圍繞著方法執行
實現:在result結果輸出前會有一個提示語句輸出。
LoggingAspect.java:
1 package com.hk.spring.aop.impl; 2 3 import java.util.Arrays; 4 import java.util.List; 5 import org.aspectj.lang.JoinPoint;6 import org.aspectj.lang.annotation.Aspect; 7 import org.aspectj.lang.annotation.Before; 8 import org.springframework.stereotype.Component; 9 10 //把這個類聲明為一個切面。步驟:需要把該類放入到IOC容器中,然後再聲明為一個切面。 11 @Aspect 12 @Component 13 public class LoggingAspect { 14 //聲明該方法是一個前置通知:在目標方法之前執行 15 @Before("execution(public int com.hk.spring.aop.impl.ArithmeticCalculator.add(int,int))") 16 public void beforeMethod(JoinPoint joinPoint){ 17 String methodName = joinPoint.getSignature().getName(); 18 List<Object> args = Arrays.asList(joinPoint.getArgs()); 19 System.out.println("The method " + methodName + " begins with " + args); 20 } 21 }
applicationContext.xml:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:aop="http://www.springframework.org/schema/aop" 5 xmlns:context="http://www.springframework.org/schema/context" 6 xsi:schemaLocation="http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans.xsd 8 http://www.springframework.org/schema/context 9 http://www.springframework.org/schema/context/spring-context-4.3.xsd 10 http://www.springframework.org/schema/aop 11 http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> 12 13 <!-- 配置自動掃描的包 --> 14 <context:component-scan base-package="com.hk.spring.aop.impl"></context:component-scan> 15 16 <!-- 使AspectJ 註解起作用:自動為匹配的類生成代理對象 --> 17 <aop:aspectj-autoproxy></aop:aspectj-autoproxy> 18 </beans>
Main.java:
1 package com.hk.spring.aop.impl; 2 3 import org.springframework.context.ApplicationContext; 4 import org.springframework.context.support.ClassPathXmlApplicationContext; 5 6 public class Main { 7 public static void main(String[] args) { 8 //1.創建Spring的IOC容器 9 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); 10 11 //2.從IOC容器中獲取Bean的實例 12 ArithmeticCalculator arithmeticCalculator = ctx.getBean(ArithmeticCalculator.class); 13 //3.使用bean 14 int result = arithmeticCalculator.add(3, 6); 15 System.out.println("result:" + result); 16 } 17 18 }
運行結果:
假如在Main.java代碼最後再加入:
1 result = arithmeticCalculator.div(12, 6); 2 System.out.println("result:" + result);
要使切面代碼對該句也有效,需要在切面代碼中把add改為*,否則不會有效,下圖示:
註:如果不改動代碼仍為add,那就是表明只對add方法有效。
【利用方法簽名編寫AspectJ切入點表達式】
1.最典型的切入點表達式是根據方法的簽名來匹配各種方法
--execution * com.hk.spring.aop.impl.ArithmeticCalculator.*(..):匹配ArithmeticCalculator中聲明的所有方法,第一個 “ * ” 代表任意修飾符以及任意返回值,第二個“ * ” 代表任意方法。“ .. ”匹配任意數量的參數。若目標類與接口與該切面在同一個包中,可以省略包名。
--execution public* ArithmeticCalculator.*(..):匹配ArithmeticCalculator接口的所有公有方法。
--execution public double ArithmeticCalculator.*(..):匹配ArithmeticCalculator中返回double類型數值的方法。
--execution public double ArithmeticCalculator.*(double,..):匹配第一個參數為double類型的方法,“ .. ” 匹配任意數量任意類型的參數。
--execution public double ArithmeticCalculator.*(double,double):匹配參數類型為 double,double 類型的方法。
運行結果:
【讓通知訪問當前連接點的細節】
可以在通知方法中聲明一個類型為JoinPoint的參數。然後就能訪問鏈接細節。如方法名稱和參數值。
附:
小結:
1.Spring AOP
(1)加入jar包:
(2)在配置文件中加入AOP命名空間。
(3)基於註解的方式
①在配置文件中加入如下配置:
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
②把橫切關註點的代碼抽象到切面的類中。
(i)切面首先是一個IOC中的Bean,即加入 @Component 註解
(ii)切面還需要@Aspect 註解
③在類中聲明各種通知:
(i)聲明一個方法
(ii)在一個方法前加入@Before註解
④可以在通知方法中聲明一個類型為JoinPoint的參數。然後就能訪問鏈接細節。如方法名稱和參數值。
1 //把這個類聲明為一個切面。步驟:需要把該類放入到IOC容器中,然後再聲明為一個切面。 2 @Aspect 3 @Component 4 public class LoggingAspect { 5 //聲明該方法是一個前置通知:在目標方法之前執行 6 @Before("execution(public int com.hk.spring.aop.impl.ArithmeticCalculator.*(int,int))") 7 public void beforeMethod(JoinPoint joinPoint){ 8 String methodName = joinPoint.getSignature().getName(); 9 List<Object> args = Arrays.asList(joinPoint.getArgs()); 10 System.out.println("The method " + methodName + " begins with " + args); 11 }
前置通知