一步一步深入spring(5)--使用基於注解的spring實現 AOP


1.要利用spring aop,至少需要添加以下jar包

使用spring需要的jar
spring.jar 、commons-logging.jar

使用切面編程(AOP)需要的jar

aspectjrt.jar、aspectjweaver.jar、cglib-nodep-2.1_3.jar

使用JSR-250提供的注解,如@Resource,需要的jar

common-annotations.jar

2.使用spring 進行aop編程,首先我們要在Spring的配置文件中引入aop命名空間:

1 <beans xmlns=http://www.springframework.org/schema/beans
2 xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
3 xmlns:aop=http://www.springframework.org/schema/aop
4 xsi:schemaLocation=”http://www.springframework.org/schema/beans
5 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
6 http://www.springramework.org/schema/aop
7 http://www.springframework.org/schema/aop/spring-aop-2.5.xsd”>
8 
9 </beans>

當然我們在使用spring的時候,肯定會使用到spring ioc相關的內容,也需要加入命名空間對IOC部分的支持

3.使用注解方式來實現aop,首先需要在spring的配置文件中啟動對@AspectJ注解的支持

<aop:aspectj-autoproxy/>

4.建立一個類,作為切面類,然后在切面類中依次添加切入點,前置通知,后置通知,例外通知,最終通知,環繞通知等:

完整的java文件:

 1 package com.yangyang.aop;
 2 
 3 import org.aspectj.lang.ProceedingJoinPoint;
 4 import org.aspectj.lang.annotation.After;
 5 import org.aspectj.lang.annotation.AfterReturning;
 6 import org.aspectj.lang.annotation.AfterThrowing;
 7 import org.aspectj.lang.annotation.Around;
 8 import org.aspectj.lang.annotation.Aspect;
 9 import org.aspectj.lang.annotation.Before;
10 import org.aspectj.lang.annotation.Pointcut;
11 
12 //聲明該類為一個切面
13 @Aspect 
14 public class MyInterceptor {
15      //切入點要攔截的類
16     @Pointcut("execution (* com.yangyang.service..*.*(..))")
17     private void anyMethod(){} //聲明一個切入點,切入點的名稱其實是一個方法
18 
19     //前置通知(不需要獲取輸入參數)
20     @Before("anyMethod()")//第一個參數為切入點的名稱
21     public void doAccessCheck(){
22         System.out.println("前置通知");
23     }
24     
25     //后置通知(不需要獲取返回值)
26     @AfterReturning("anyMethod()")
27     public void doAfterReturning(){
28         System.out.println("后置通知:");
29     }
30     
31     //例外通知(不需要異常信息)
32     @AfterThrowing("anyMethod()")
33     public void doAfterThrowing(){
34         System.out.println("例外通知");
35     }
36     
37     //最終通知
38     @After("anyMethod()")
39     public void doAfter(){
40         System.out.println("最終通知");
41     }
42     
43     //環繞通知(特別適合做權限系統)
44     @Around("anyMethod()")
45     public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable{
46         System.out.println("環繞通知進入方法");
47         Object object=pjp.proceed();
48         System.out.println("環繞通知退出方法");
49         return object;
50     }
51     
52 }

5.建立供測試的業務方法:這里只列出實現:

 1 package com.yangyang.service.impl;
 2 
 3 import com.yangyang.service.PersonService;
 4 
 5 public class PersonServiceImpl implements PersonService{
 6 
 7     @Override
 8     public String getNameById(Long id) {
 9         System.out.println("我是getNameById()方法");
10         return "csy";
11     }
12 
13     @Override
14     public void save(String name) {
15         throw new RuntimeException("故意拋出了異常,僅供測試");
16     //    System.out.println("我是save()方法");
17     }
18 
19     @Override
20     public void update(String name, Long id) {
21         System.out.println("我是update()方法");
22     }
23 
24 }

6.將業務service的bean以及切面的類加入spring管理,完整的配置文件如下:

 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:context="http://www.springframework.org/schema/context"
 5         xmlns:aop="http://www.springframework.org/schema/aop"    
 6         xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
 7             http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
 8             http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
 9  <!-- 加上aop的命名空間以及DTD驗證 -->
10  
11  
12      <aop:aspectj-autoproxy/><!-- 打開aop對@Aspectj的注解支持 ,相當於為注解提供解析功能-->
13      
14      <bean id="myInterceptor" class="com.yangyang.aop.MyInterceptor"></bean>
15      
16     <bean id="personService" class="com.yangyang.service.impl.PersonServiceImpl">
17     </bean>
18     
19 </beans>

7.編寫單元測試,來測試aop是否成功實現。代碼:

1 @Test
2     public void testSpringInterceptor() {
3         ApplicationContext ctx=new ClassPathXmlApplicationContext("resources/beans.xml");
4         PersonService personService=(PersonService)ctx.getBean("personService");
5         personService.getNameById(1l);
6         System.out.println("----------------------------------");
7         personService.save("csy");
8     }

觀察結果如下:

前置通知
環繞通知進入方法
我是getNameById()方法
后置通知:
最終通知
環繞通知退出方法
----------------------------------
前置通知
環繞通知進入方法
例外通知
最終通知

可以看出AOP編寫成功了。

思考一個問題,如果我們希望獲取在業務操作在使用aop的服務時得到相應的輸入,返回值,以及異常信息,那么切面該怎么改呢:

只需要在各自通知的地方加入相應類型的參數即可:

 1 package com.yangyang.aop;
 2 
 3 import org.aspectj.lang.ProceedingJoinPoint;
 4 import org.aspectj.lang.annotation.After;
 5 import org.aspectj.lang.annotation.AfterReturning;
 6 import org.aspectj.lang.annotation.AfterThrowing;
 7 import org.aspectj.lang.annotation.Around;
 8 import org.aspectj.lang.annotation.Aspect;
 9 import org.aspectj.lang.annotation.Before;
10 import org.aspectj.lang.annotation.Pointcut;
11 
12 //聲明該類為一個切面
13 @Aspect 
14 public class MyInterceptor {
15      //切入點要攔截的類
16     @Pointcut("execution (* com.yangyang.service..*.*(..))")
17     private void anyMethod(){} //聲明一個切入點,切入點的名稱其實是一個方法
18 
19     //前置通知(獲取輸入參數)
20     @Before("anyMethod() && args(name)")//第一個參數為切入點的名稱,第二個是測試獲取輸入參數,此處為string類型的,參數名稱與方法中的名稱相同,如果不獲取輸入參數,可以不要
21     public void doAccessCheck(String name){
22         System.out.println("前置通知:"+name);
23     }
24     
25     //后置通知(獲取返回值)
26     @AfterReturning (pointcut="anyMethod()", returning="result")
27     public void doAfterReturning(String result){
28         System.out.println("后置通知:"+result);
29     }
30 
31     //例外通知(獲取異常信息)
32     @AfterThrowing(pointcut="anyMethod()",throwing="e")
33     public void doAfterThrowing(Exception e){
34         System.out.println("例外通知:"+e);
35     }
36     
37     //最終通知
38     @After("anyMethod()")
39     public void doAfter(){
40         System.out.println("最終通知");
41     }
42     
43     //環繞通知(特別適合做權限系統)
44     @Around("anyMethod()")
45     public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable{
46         System.out.println("環繞通知進入方法");
47         Object object=pjp.proceed();
48         System.out.println("環繞通知退出方法");
49         return object;
50     }
51     
52 }

同理執行單元測試,可以看到結果:

環繞通知進入方法
我是getNameById()方法
后置通知:csy
最終通知
環繞通知退出方法
----------------------------------
前置通知:csy
環繞通知進入方法
例外通知:java.lang.RuntimeException: 故意拋出了異常,僅供測試
最終通知

這樣我們的功能就開發完了

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM