環境 :
eclipse 3.6
maven 3.0.4
spring 3.0.5
aspectj 1.6.11
pom.xml 清單 :
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.fancy</groupId>
<artifactId>spring-aop</artifactId>
<packaging>war</packaging>
<version>1.0</version>
<name>spring-aop Maven Webapp</name>
<url>http://maven.apache.org</url>
<properties>
<spring.version>3.0.5.RELEASE</spring.version>
<aspectj.version>1.6.11</aspectj.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Spring AOP + AspectJ -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>spring-aop</finalName>
</build>
</project>
applicationContext.xml 清單 :
<?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:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- 開啟注解 -->
<context:annotation-config/>
<!-- 自動掃描 -->
<context:component-scan base-package="com.fancy"/>
<!-- 啟動 AspectJ 支持 -->
<aop:aspectj-autoproxy />
</beans>
還是來編寫 HelloWorld :
1 . 編寫 HelloWorld 接口
package com.fancy.service;
public interface HelloWorld {
public void sayHi();
public void sayHiAround(String username);
public void sayHiThrowException() throws Exception;
public String sayHiReturnValue();
}
2 . 編寫 HelloWorld 接口的實現,并將其注解成 spring 的一個組件
package com.fancy.service.impl;
import com.fancy.service.HelloWorld;
import org.springframework.stereotype.Component;
@Component
public class HelloWorldImpl implements HelloWorld {
public void sayHi() {
System.out.println("sayHi ---->> Hi fancy !");
}
public void sayHiAround(String username) {
System.out.println("sayHiAround ---->> Hi " + username + " !");
}
public void sayHiThrowException() throws Exception {
System.out.println("sayHiThrowException ---->> Hi fancy !");
throw new Exception("Throw an exception here !!!!");
}
public String sayHiReturnValue() {
System.out.println("sayHiReturnValue ---->> Hi fancy !");
return "fancy";
}
}
3 . 編寫方面代碼 :
AspectJ @Before 示例
package com.fancy.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class MyAspect {
@Before("execution (* com.fancy.service.HelloWorld.sayHi(..))")
public void logBefore(JoinPoint joinPoint){
System.out.println("logBefore() Method Invoke!");
System.out.println("Hijack Method Name : " + joinPoint.getSignature().getName());
}
}
其中,@Before("execution (* com.fancy.service.HelloWorld.sayHi(..))") 中的 execution (* com.fancy.service.HelloWorld.sayHi(..)) 是切入點表達式,
更多的幫助信息可以查看 spring 的幫助文檔,spring 3.0.5 的幫助文檔中是在 第 7 章的 7.2.3.4 小節,因為文檔上說的也不是太清楚,在這里我也不好說話,
其中的 execution 是用于匹配方法執行的連接點,那個 * 號所占的位不知道是不是代表方法的訪問權限,文檔上沒說,網上也沒找到相關解釋,哪位知道的望告知啊~~
接下來的 com.fancy.service.HelloWorld.sayHi 就很明顯了,就是切入點方法名,再接下來的是 (..),(..) 代表匹配任意數量的參數,可以是 0 個也可以是多個 ;
如果你確定這個方法不需要參數,可以直接使用 (),還可以使用 (*) 來匹配一個任意類型的參數,還可以使用 (* , String),這樣代表匹配兩個參數,第二個參數必須是
String 類型的參數,這些在 spring 幫助文檔的 7.2.3.4 小節都有說到,在這里就不多說了,可以自己去看,英文的看起來更帶勁 *_*
再接下來的是 JoinPoint 接口,org.aspectj.lang.JoinPoint 接口表示的是目標類連接點對象,這個我也找不到相關的 API,只能手工整理一下了 :
JoinPoint API
java.lang.Object getThis() :獲取代理對象本身;
java.lang.Object getTarget() :獲取連接點所在的目標對象;
Signature getSignature() :獲取連接點的方法簽名對象;
java.lang.Object[] getArgs():獲取連接點方法運行時的入參列表;
Junit 測試
package junit.test;
import org.junit.Test;
import org.junit.BeforeClass;
import com.fancy.service.HelloWorld;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestApp {
private static ApplicationContext context = null;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
context = new ClassPathXmlApplicationContext("applicationContext.xml");
}
@Test
public void testMethod() throws Exception{
HelloWorld helloworld = (HelloWorld)context.getBean("helloWorldImpl");
helloworld.sayHi();
}
}
后臺輸出 :
logBefore() Method Invoke!
Hijack Method Name : sayHi
sayHi ---->> Hi fancy !
AspectJ @After 示例
package com.fancy.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class MyAspect {
@After("execution (* com.fancy.service.HelloWorld.sayHi(..))")
public void logAfter(JoinPoint joinPoint){
System.out.println("logAfter() Method Invoke!");
System.out.println("Hijack Method Name : " + joinPoint.getSignature().getName());
}
}
Junit 測試
@Test
public void testMethod() throws Exception{
HelloWorld helloworld = (HelloWorld)context.getBean("helloWorldImpl");
helloworld.sayHi();
}
后臺輸出 :
sayHi ---->> Hi fancy !
logAfter() Method Invoke!
Hijack Method Name : sayHi
AspectJ @AfterReturning 示例
package com.fancy.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class MyAspect {
@AfterReturning(pointcut = "execution (* com.fancy.service.HelloWorld.sayHiReturnValue(..))", returning = "returnValue")
public void logAfterReturning(JoinPoint joinPoint, Object/*String*/ returnValue){
System.out.println("logAfterReturning() Method Invoke!");
System.out.println("Hijack Method Name : " + joinPoint.getSignature().getName());
System.out.println("The Return Value Is : " + returnValue);
}
}
Junit 測試
@Test
public void testMethod() throws Exception{
HelloWorld helloworld = (HelloWorld)context.getBean("helloWorldImpl");
helloworld.sayHiReturnValue();
}
后臺輸出 :
sayHiReturnValue ---->> Hi fancy !
logAfterReturning() Method Invoke!
Hijack Method Name : sayHiReturnValue
The Return Value Is : fancy
AspectJ @AfterThrowing 示例
package com.fancy.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class MyAspect {
@AfterThrowing(pointcut = "execution (* com.fancy.service.HelloWorld.sayHiThrowException(..))", throwing = "error")
public void logAfterThrowing(JoinPoint joinPoint, Throwable error){
System.out.println("logAfterThrowing() Method Invoke!");
System.out.println("Hijack Method Name : " + joinPoint.getSignature().getName());
System.out.println("Exception Message :" + error);
}
}
Junit 測試
@Test
public void testMethod() throws Exception{
HelloWorld helloworld = (HelloWorld)context.getBean("helloWorldImpl");
helloworld.sayHiThrowException();
}
后臺輸出 :
sayHiThrowException ---->> Hi fancy !
logAfterThrowing() Method Invoke!
Hijack Method Name : sayHiThrowException
Exception Message :java.lang.Exception: Throw an exception here !!!!
若將 HelloWorldImpl 類中 sayHiThrowException 方法的異常拋出注釋掉,
public void sayHiThrowException() throws Exception {
System.out.println("sayHiThrowException ---->> Hi fancy !");
//throw new Exception("Throw an exception here !!!!");
}
其余不變,再次執行 Junit 測試,后臺輸出 :
sayHiThrowException ---->> Hi fancy !
這就說明,當該方法能夠運行正常的時候,沒有拋出異常,則,logAfterThrowing 不會被執行 .
AspectJ @Around 示例
package com.fancy.aspect;
import java.util.Arrays;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class MyAspect {
@Around("execution (* com.fancy.service.HelloWorld.sayHiAround(..))")
public void logAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("logAround() Method Invoke!");
System.out.println("Hijack Method Name : " + joinPoint.getSignature().getName());
System.out.println("Hijack Arguments Is : " + Arrays.toString(joinPoint.getArgs()));
System.out.println("Around before : can do something here !");
joinPoint.proceed(); //放行
System.out.println("Around after : can do something here !");
}
}
Junit 測試
@Test
public void testMethod() throws Exception{
HelloWorld helloworld = (HelloWorld)context.getBean("helloWorldImpl");
helloworld.sayHiAround("fancy");
}
后臺輸出 :
logAround() Method Invoke!
Hijack Method Name : sayHiAround
Hijack Arguments Is : [fancy]
Around before : can do something here !
sayHiAround ---->> Hi fancy !
Around after : can do something here !
其中,需要提一下 ProceedingJoinPoint 接口 :
ProceedingJoinPoint 繼承于 JoinPoint,是其子接口,它新增了兩個用于執行連接點方法的方法:
java.lang.Object proceed() throws java.lang.Throwable:通過反射執行目標對象的連接點處的方法;
java.lang.Object proceed(java.lang.Object[] args) throws java.lang.Throwable:通過反射執行目標對象連接點處的方法,不過使用新的入參替換原來的入參。
最后附上 spring 3.0.5 幫助文檔中的一些信息 :
Some examples of common pointcut expressions are given below.
-
the execution of any public method:
execution(public * *(..))
-
the execution of any method with a name beginning with "set":
execution(* set*(..))
-
the execution of any method defined by the AccountService
interface:
execution(* com.xyz.service.AccountService.*(..))
-
the execution of any method defined in the service package:
execution(* com.xyz.service.*.*(..))
-
the execution of any method defined in the service package or a sub-package:
execution(* com.xyz.service..*.*(..))
-
any join point (method execution only in Spring AOP) within the service package:
within(com.xyz.service.*)
-
any join point (method execution only in Spring AOP) within the service package or a sub-package:
within(com.xyz.service..*)
-
any join point (method execution only in Spring AOP) where the proxy implements the AccountService
interface:
this(com.xyz.service.AccountService)
'this' is more commonly used in a binding form :- see the following section on advice for how to make the proxy object available in the advice body.
-
any join point (method execution only in Spring AOP) where the target object implements the AccountService
interface:
target(com.xyz.service.AccountService)
'target' is more commonly used in a binding form :- see the following section on advice for how to make the target object available in the advice body.
-
any join point (method execution only in Spring AOP) which takes a single parameter, and where the argument passed at runtime is Serializable
:
args(java.io.Serializable)
Note that the pointcut given in this example is different to execution(* *(java.io.Serializable))
: the args version matches if the argument passed at runtime is Serializable, the execution version matches if the method signature declares a single parameter of type Serializable
.
-
any join point (method execution only in Spring AOP) where the target object has an @Transactional
annotation:
@target(org.springframework.transaction.annotation.Transactional)
'@target' can also be used in a binding form :- see the following section on advice for how to make the annotation object available in the advice body.
-
any join point (method execution only in Spring AOP) where the declared type of the target object has an @Transactional
annotation:
@within(org.springframework.transaction.annotation.Transactional)
'@within' can also be used in a binding form :- see the following section on advice for how to make the annotation object available in the advice body.
-
any join point (method execution only in Spring AOP) where the executing method has an @Transactional
annotation:
@annotation(org.springframework.transaction.annotation.Transactional)
'@annotation' can also be used in a binding form :- see the following section on advice for how to make the annotation object available in the advice body.
-
any join point (method execution only in Spring AOP) which takes a single parameter, and where the runtime type of the argument passed has the@Classified
annotation:
@args(com.xyz.security.Classified)
'@args' can also be used in a binding form :- see the following section on advice for how to make the annotation object(s) available in the advice body.
-
any join point (method execution only in Spring AOP) on a Spring bean named 'tradeService
':
bean(tradeService)
-
any join point (method execution only in Spring AOP) on Spring beans having names that match the wildcard expression '*Service
':
bean(*Service)
posted on 2012-10-05 00:31
fancydeepin 閱讀(4849)
評論(1) 編輯 收藏