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