1. 程式人生 > >Spring框架之Spring AOP

Spring框架之Spring AOP

權限 保持 eth before app spring win 應該 ctc

一、基於註解管理的AOP 1、Spring配置文件 <!-- 配置自動掃描包,自動掃描Bean組件,切面類 --> <context:component-scan base-package="com.zhoujian.spring.anno,com.zhoujian.spring.test"> <!-- <context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/> --> </context:component-scan> <!-- 啟動@Aspectj支持 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> 2、切面類 package com.zhoujian.spring.aspect; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Aspect @Component /** * 如何聲明一個切面類: 首先是放入IOC容器進行管理, 其次是需要Aspect進行修飾 * */ public class AuthAspectClass { @Before(value = "execution(* com.zhoujian.spring.anno.*.*(..))") // @Before("execution(* com.zhoujian.spring.test.*.*(..))") public void before() { System.out.println("模擬進行權限檢查..."); } @After("execution(* com.zhoujian.spring.anno.*.*(..))") public void after() { /** * after增強處理,不管目標方法是如何結束的,該方法會在目標方法結束之後被織入 * 如果對同一目標方法進行了after和afterReturning增強處理且目標方法正常執行結束, * 此時會先織入after增強處理,之後才是afterReturning增強處理, * 如果目標方法非正常結束, 那麽只會在目標方法結束之後,織入after增強處理, * 如果目標方法的非正常結束拋出了異常,伴兒會在目標方法結束之後,先織入after增強處理, * 之後才會織入afterThrowing增強處理 */ System.out.println("關閉當前事務..."); } @AfterReturning(returning = "returnVal", value = "execution(* com.zhoujian.spring.anno.*.*(..))") public void afterReturning(Object returnVal) { System.out.println("目標方法的返回值:" + returnVal); System.out.println("只有目標方法正常執行完成後,才會執行AfterReturning..."); } @AfterThrowing(throwing="exception",value="execution(void com.zhoujian.spring.anno.HelloImpl.getSub())") public void afterThrowing(Exception exception){ System.out.println("只有執行com.zhoujian.spring.anno.HelloImpl.getSub() 該方法 ,才會進行增強"); System.out.println("目標方法拋出的異常為: " + exception.getMessage()); System.out.println("模擬Advice進行異常處理..."); } @Around("execution(public int com.zhoujian.spring.anno.HelloImpl.total(..))") public Object around(ProceedingJoinPoint joinPoint){ /** * Around增強處理是一個很強大,但是通常需要在一個線程安全的環境使用(比如在proceed方法調用前後需要共享數據) */ Object result = null; try { Object[] args = {6,3,"4"}; /** * 在這裏傳入一個Object數組,可以替換目標方法中的實參,偷天換日 * 但是,傳入參數的個數和類型應該與目標方法保持一致 * 如果個數少於目標方法參數個數或者類型不匹配都會拋出異常 * 如果是 個數多余目標方法參數個數,那麽會從數組下標0開始往後取出相同個數作為實參,此時如果取出的數組元素 * 類型與目標方法類型不匹配,那麽也會拋出異常 */ System.out.println(joinPoint.getThis()); System.out.println(joinPoint.getTarget()); result = joinPoint.proceed(args); } catch (Throwable e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(result); /** * return 返回值時 也可以進行目標方法返回值的修改,偷天換日 */ return result; } } 3、業務類 package com.zhoujian.spring.anno; import org.springframework.stereotype.Component; @Component public class HelloImpl implements Hello { @Override public void foo() { System.out.println("執行Hello組件的 foo()方法..."); } @Override public int addUser(String name, String pass) { System.out.println("執行Hello組件的addUser()方法添加用戶: " + name); return 10; } public void getSub(){ System.out.println("執行Hello組件的getSub()方法..."); int num = 12; if(num % 2 == 0){ throw new NullPointerException("假裝我是一個空指針異常..."); } } } 4、測試方法 @Test public void beanTest(){ ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); HelloImpl he = ac.getBean(HelloImpl.class); // System.out.println(he.getClass()); he.foo(); he.addUser("張三", "123456"); he.getSub(); } 5、定義切入點 package com.zhoujian.spring.aspect; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; @Aspect @Component public class LogAspectClass { /** * 使用 @Pointcut 定義一個切入點,方法返回類型必須是void * 因為這僅僅只是一個簽名形式的方法,為了聲明切入點的名稱,不需要方法體,所以方法體也為空 * 如果需要在其他的切面類中進行引用時,必須遵循Java的權限訪問控制標準, * 采用類名為前綴: value="LogAspectClass.myPointcut()" * 或者 pointcut="LogAspectClass.myPointcut()" */ @Pointcut("execution(* com.zhoujian.spring.anno.*.*(..))") public void myPointcut(){} @Before(value="myPointcut()") public void beforeLog(){ System.out.println("使用定義好的切入點"); } } 二、基於XML管理的AOP 1、Spring配置文件 <!-- 切面類 --> <bean id="logAspectClassWithXML" class="com.zhoujian.spring.aspect.LogAspectClassWithXML"></bean> <!-- helloImpl 實現了 Hello 接口 --> <bean id="helloImpl" class="com.zhoujian.spring.anno.HelloImpl"></bean> <!-- helloImpl2 是一個單實體類,沒有繼承任何類和 實現任何接口 --> <bean id="helloImpl2" class="com.zhoujian.spring.anno.HelloImpl2"></bean> <!-- fordCarChild 繼承了FordCar類--> <bean id="fordCarChild" class="com.zhoujian.spring.anno.FordCarChild"></bean> <!-- AOP 配置 --> <aop:config> <aop:aspect id="logAspect" ref="logAspectClassWithXML" order="1"> <aop:before method="beforeLog" pointcut="execution(* com.zhoujian.spring.anno.*.*(..))"/> </aop:aspect> </aop:config> 2、切面類和相關實體類 Hello接口 package com.zhoujian.spring.anno; public interface Hello { public void foo(); public int addUser(String name, String pass); } Hello實現類 HelloImpl package com.zhoujian.spring.anno; public class HelloImpl implements Hello { @Override public void foo() { System.out.println("執行Hello組件的 foo()方法..."); } @Override public int addUser(String name, String pass) { System.out.println("執行Hello組件的addUser()方法添加用戶: " + name); return 10; } public void getSub(){ System.out.println("執行Hello組件的getSub()方法..."); int num = 12; if(num % 2 == 0){ throw new NullPointerException("假裝我是一個空指針異常..."); } } public int total(int a, int b){ int total = a + b; return total; } } 單實體類 HelloImpl2 package com.zhoujian.spring.anno; public class HelloImpl2{ public void foo() { System.out.println("執行Hello組件的 foo()方法..."); } public int addUser(String name, String pass) { System.out.println("執行Hello組件的addUser()方法添加用戶: " + name); return 10; } public void getSub(){ System.out.println("執行Hello組件的getSub()方法..."); int num = 12; if(num % 2 == 0){ throw new NullPointerException("假裝我是一個空指針異常..."); } } public int total(int a, int b){ int total = a + b; return total; } } 切面類 LogAspectClassWithXML package com.zhoujian.spring.aspect; import org.apache.catalina.tribes.util.Arrays; import org.aspectj.lang.JoinPoint; public class LogAspectClassWithXML { public void beforeLog(JoinPoint point){ System.out.println("Before:增強的目標方法名為:" + point.getSignature().getName()); System.out.println("Before:增強的目標方法的參數為:" + Arrays.toString(point.getArgs())); System.out.println("Before:被織入增強的目標對象為:" + point.getTarget()); } public void after(JoinPoint point) { /** * after增強處理,不管目標方法是如何結束的,該方法會在目標方法結束之後被織入 * 如果對同一目標方法進行了after和afterReturning增強處理且目標方法正常執行結束, * 此時會先織入after增強處理,之後才是afterReturning增強處理, * 如果目標方法非正常結束, 那麽只會在目標方法結束之後,織入after增強處理, * 如果目標方法的非正常結束拋出了異常,那麽會在目標方法結束之後,先織入after增強處理, * 之後才會織入afterThrowing增強處理 */ System.out.println("After: 目標方法結束後釋放資源..."); System.out.println("After:增強的目標方法名為:" + point.getSignature().getName()); System.out.println("After:增強的目標方法的參數為:" + Arrays.toString(point.getArgs())); System.out.println("After:被織入增強的目標對象為:" + point.getTarget()); } public void afterReturning(JoinPoint point, Object returnVal) { System.out.println("AfterReturning: 獲取目標方法的返回值" + returnVal); System.out.println("AfterReturning:增強的目標方法名為:" + point.getSignature().getName()); System.out.println("AfterReturning:增強的目標方法的參數為:" + Arrays.toString(point.getArgs())); System.out.println("AfterReturning:被織入增強的目標對象為:" + point.getTarget()); } public void afterThrowing(JoinPoint point, Exception exception, String name, String age){ System.out.println("AfterThrowing: 獲取到目標方法拋出的異常" + exception.getMessage()); System.out.println("AfterThrowing:增強的目標方法名為:" + point.getSignature().getName()); System.out.println("AfterThrowing:增強的目標方法的參數為:" + Arrays.toString(point.getArgs())); System.out.println("AfterThrowing:被織入增強的目標對象為:" + point.getTarget()); } } 3、測試類 AspectWithXMLTest package com.zhoujian.spring.test; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.zhoujian.spring.anno.HelloImpl2; public class AspectWithXMLTest { @Test public void test() { ApplicationContext ac = new ClassPathXmlApplicationContext("aspectWithXML.xml"); System.out.println(ac.getBean("helloImpl").getClass().getName()); /** * helloImpl 實體類實現了一個接口,所以其代理類的獲取必須使用其實現的接口進行獲取,不然會發生類型轉換異常 */ com.zhoujian.spring.anno.Hello hel = (com.zhoujian.spring.anno.Hello) ac.getBean("helloImpl"); hel.foo(); } public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("aspectWithXML.xml"); /** * 單實體類:即沒有繼承和實現任何類和接口的實體類, 在獲取其代理對象的時候,直接獲取就行了 * 即使目標類繼承了一個或者多個類,獲取時正常獲取即可,用其父類進行獲取也行 */ System.out.println(ac.getBean("helloImpl").getClass().getName()); HelloImpl2 hel = (HelloImpl2) ac.getBean("helloImpl2"); hel.foo(); } } 註:Spring AOP 由 IOC 容器進行生成和管理,當進行IOC容器創建的時候,IOC容器會掃描切入點表達式所包含的所有包中所有類,並為所有類創建代理對象
如果目標類沒有實現任何的接口,Spring將會是cglib方式創建代理對象; 如果目標類實現了一個或多個接口或者,那麽Spring將會采用JDK動態代理創建代理類(此時代理類的獲取必須使用接口類型接收) 使用Spring版本:spring-framework-4.3.10.RELEASE-dist

Spring框架之Spring AOP