Java Spring-AspectJ

 

Spring的AspectJ的AOP
AspectJ 是一個面向切面的框架,它擴展了 Java 語言。 AspectJ 定義了 AOP 語法所以它有一個專門的編譯器用來生成遵守 Java 字節編碼規範的 Class 文件。
AspectJ 是一個基於 Java 語言的 AOP 框架,Spring2.0 以後新增了對 AspectJ 切點表達式支持
@AspectJ  是 AspectJ1.5 新增功能,通過 JDK5 註解技術,允許直接在 Bean 類中定義切面
新版本 Spring 框架,建議使用 AspectJ 方式來開發 AOP。

  • AspectJ 表達式

在使用spring框架配置AOP的時候,不管是通過XML配置文件還是註解的方式都需要定義pointcut"切入點"。

execution(<修飾符模式>? <返回類型模式> <方法名模式>(<參數模式>) <異常模式>?)  

除了返回類型模式、方法名模式和參數模式外,其它項都是可選的

實例:

1

2

3

4

5

6

7

8

9

10

11

execution (* com.sample.service.impl..*.*(..))

 整個表達式可以分爲五個部分:

 1、execution(): 表達式主體。

 2、第一個*號:表示返回類型,*號表示所有的類型。

 3、包名:表示需要攔截的包名,後面的兩個句點表示當前包和當前包的所有子包,com.sample.service.impl包、子孫包下所有類的方法。

 4、第二個*號:表示類名,*號表示所有的類。

 5、*(..):最後這個星號表示方法名,*號表示所有的方法,後面括弧裏面表示方法的參數,兩個句點表示任何參數。

 

execution(“* cn.spring3.demo1.dao.*(..)”) --- 只匹配當前包

execution(“* cn.spring3.demo1.dao..*(..)”) --- 匹配包及當前包的子包 .

execution(* cn.dao.GenericDAO+.*(..)) --- 匹配 GenericDAO 及子類<br>execution(* save*(..)) ---匹配所有save開頭的方法

  • AspectJ增強方式

@Before  前置通知,相當於 BeforeAdvice
@AfterReturning  後置通知,相當於 AfterReturningAdvice
@Around  環繞通知,相當於 MethodInterceptor
@AfterThrowing 拋出通知,相當於 ThrowAdvice
@After  最終 final 通知,不管是否異常,該通知都會執行
@DeclareParents  引介通知,相當於 IntroductionInterceptor

一、基於註解的方式

開發步驟:

  • 第一步 : 引入相應 jar 包 
    * aspectj 依賴 aop 環境 .
    * spring-aspects-3.2.0.RELEASE.jar
    * com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
  • 第二步 : 編寫目標類
  • 第三步 : 使用AspectJ註解自定義切面類,就是切點與增強結合
  • 第四步 : 配置XML
    *  引入 aop 的約束 :
    * <aop:aspectj-autoproxy /> ---  自動生成代理 :
    *  底層就是 AnnotationAwareAspectJAutoProxyCreator

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

// 類

public class Student {

    public void add(){

        System.out.println("添加方法...");

    }

 

    public void delete(){

        System.out.println("刪除方法...");

    }

}

 

// 切面

@Aspect

public class MyAspect {

    @Before("execution(* spring2..*.add*(..))")

    void before(){

        System.out.println("前置增強...");

    }

}

 

// 測試

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration("classpath:config3.xml")

public class Demo {

 

    @Resource(name = "stu")

    private Student s;

    @Test

    public void demo(){

        s.add();

    }

}

配置XML:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="

        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

 

     <!--自動生成代理,底層就是 AnnotationAwareAspectJAutoProxyCreator-->

    <aop:aspectj-autoproxy/>

 

    <bean id="stu" class="spring2.Student"/>

 

    <!--需要把切面類進行註冊,才能自動生成代理-->

    <bean id="myaspect" class="spring2.MyAspect"/>

</beans>

* 其他的增強的使用:

AspectJ的通知類型:
@Before 前置通知,相當於BeforeAdvice
* 就在方法之前執行.沒有辦法阻止目標方法執行的.
@AfterReturning 後置通知,相當於AfterReturningAdvice
* 後置通知,獲得方法返回值.
@Around 環繞通知,相當於MethodInterceptor
* 在可以方法之前和之後來執行的,而且可以阻止目標方法的執行.
@AfterThrowing 拋出通知,相當於ThrowAdvice
@After 最終final通知,不管是否異常,該通知都會執行
@DeclareParents 引介通知,相當於IntroductionInterceptor

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

@Aspect

public class MyAspect {

    @Before("execution(* spring2..*.add*(..))")

    void before() {

        System.out.println("前置增強...");

    }

 

    @AfterReturning(value = "execution(* spring2..*.add*(..))", returning = "returnVal")

    public void afterReturning(Object returnVal) {

        System.out.println("後置增強..." "方法的返回值:" + returnVal);

    }

 

    @Around("execution(* spring2..*.add*(..))")

    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

        System.out.println("環繞前增強...");

        Object object = proceedingJoinPoint.proceed();

        System.out.println("環繞後增強...");

        return object;

    }

 

    @AfterThrowing(value = "execution(* spring2..*.add*(..))", throwing = "e")

    public void throwing(Throwable e) {

        System.out.println("不好,出異常了!" + e.getMessage());

    }

 

    @After("execution(* spring2..*.add*(..))")

    public void after() {

        System.out.println("最終通知...");

    }

}

* 基於AspectJ的切點定義

使用 @Pointcut 進行自定義的切點定義。

1

2

3

4

5

6

7

8

9

10

@Aspect

public class MyAspect {

    @Before("MyAspect.myPointcut()")

    void before() {

        System.out.println("前置增強...");

    }

 

    @Pointcut("execution(* spring2..*.add*(..))")

    private void myPointcut(){}

}

* Advisor和Aspect的區別

Advisor:Spring傳統意義上的切面:支持一個切點和一個通知的組合.
Aspect:可以支持多個切點和多個通知的組合.

 

二、基於XML的方式

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

/**

 * 切面類

 */

public class MyAspectXML {

    public void before() {

        System.out.println("前置通知...");

    }

 

    public void afterReturing(Object returnVal) {

        System.out.println("後置通知...返回值:" + returnVal);

    }

 

    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

        System.out.println("環繞前增強....");

        Object result = proceedingJoinPoint.proceed();

        System.out.println("環繞後增強....");

        return result;

    }

 

    public void afterThrowing(Throwable e) {

        System.out.println("異常通知..." + e.getMessage());

    }

 

    public void after() {

        System.out.println("最終通知....");

    }

}

XML配置:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

<!-- 定義切面 -->

    <bean id="myAspect" class="spring2.MyAspect"></bean>

    <!-- 定義aop配置 -->

    <aop:config>

        <!-- 定義切點: -->

        <aop:pointcut expression="execution(* cn.itcast.spring3.demo2.ProductDao.add(..))" id="mypointcut"/>

        <aop:aspect ref="myAspect">

            <!-- 前置通知 -->

            <!--  <aop:before method="before" pointcut-ref="mypointcut"/> -->

            <!-- 後置通知 -->

            <!-- < aop:after -returning method="afterReturing" pointcut-ref="mypointcut" returning="returnVal"/> -->

            <!-- 環繞通知 -->

            <!-- < aop:around method="around" pointcut-ref="mypointcut"/> -->

            <!-- 異常通知 -->

            <!-- < aop:after-throwing method="afterThrowing" pointcut-ref="mypointcut" throwing="e"/> -->

            <!-- 最終通知 -->

            <aop:after method="after" pointcut-ref="mypointcut"/>

        </aop:aspect>

    </aop:config>

 

 

 

 

 

原文  : https://www.cnblogs.com/TIMHY/p/7816812.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章