AOP-的使用

AOP 代理

Spring Aop默認是使用標準的JDK動態代碼模式來實現AOP的代理。這個方式任何接口實現的都可以被代理。

Spring AOP 也可以使用CGLIB代理的方式。這個方式代理接口不是必要的。默認的,CGLIB 使用的業務對象不是接口的實現。

啓用 @AspectJ 支持可以使用下面的java配置形式

@Configuration @EnableAspectJAutoProxy 
public class AppConfig { }

 

啓用@AspectJ使用xml的配置方式

<aop:aspectj-autoproxy/>

聲明切面

1,在應用定義一個有@Aspect 註解bean

<bean id="myAspect" class="org.xyz.NotVeryUsefulAspect">

<!-- 配置這個切面的屬性 -->

</bean>

2,一個有@Aspect 註解的NotVeryUsefulAspect 類的定義

package org.xyz;

import org.aspectj.lang.annotation.Aspect;

 

@Aspect

public class NotVeryUsefulAspect {

 

}

 

 

聲明切點

 

@Pointcut("execution(* transfer(..))")// the pointcut expression

private void anyOldTransfer() {}// the pointcut signature

 

 

Supported Pointcut Designators

支持切點的指示符 

Spring AOP支持 AspjectJ切點的指示符,可以使用的表達式如下:

execution: 匹配執行方法的切點。

within:限制切點必須包含匹配的類型。

this:匹配的切點spring aop 代理的實例返回的類型。

target: 匹配的切點spring aop 代理的實例返回的代理的對象。

args: 切點匹配的實例的參數類型。

@target: 以註解的方式來指定,匹配的切點的批執行返回對象的類型。

@args: 以註解的方式來指定,匹配的切點運行時返回的參數類型。

@within: 以註解的方式來指定,切點應當包含的類型。

@annotation: 以註解的方式,指定切點包含的子對象。

 

混合的切點表達式

 

你可以使用 &&, || and !,也可以使用通過名稱來表示。如下三個例子:

@Pointcut("execution(public * *(..))")

private void anyPublicOperation() {}



@Pointcut("within(com.xyz.someapp.trading..*)")

private void inTrading() {}



@Pointcut("anyPublicOperation() && inTrading()")

private void tradingOperation() {}

anyPublicOperation 表示切點中所有的public方法;

inTrading 匹配的是執行 trading 模塊;

tradingOperation 匹配的是在trading模塊之中的所有的public方法;

 


package com.xyz.someapp; 

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut; 
@Aspect public class SystemArchitecture 
{ 
 /** * A join point is in the web layer if the method is defined 
* in a type in the com.xyz.someapp.web package or any sub-package 
* under that. 
*/
 @Pointcut("within(com.xyz.someapp.web..*)") 
public void inWebLayer() {} 
/** 
* A join point is in the service layer if the method is defined 
* in a type in the com.xyz.someapp.service package or any sub-package 
* under that. 
*/ 
@Pointcut("within(com.xyz.someapp.service..*)") 
public void inServiceLayer() {} 
/** * A join point is in the data access layer if the method is defined 
* in a type in the com.xyz.someapp.dao package or any sub-package 
* under that. */ @Pointcut("within(com.xyz.someapp.dao..*)") 
public void inDataAccessLayer() {} 
/** 
* A business service is the execution of any method defined on a service 
* interface. This definition assumes that interfaces are placed in the
* "service" package, and that implementation types are in sub-packages. 
* 
* If you group service interfaces by functional area (for example, 
* in packages com.xyz.someapp.abc.service and com.xyz.someapp.def.service) then 
* the pointcut expression "execution(* com.xyz.someapp..service.*.*(..))" * could be used instead. 
* 
* Alternatively, you can write the expression using the 'bean'
* PCD, like so "bean(*Service)". (This assumes that you have 
* named your Spring service beans in a consistent fashion.) 
*/ 
@Pointcut("execution(* com.xyz.someapp..service.*.*(..))") 
public void businessService() {} 

/** * A data access operation is the execution of any method defined on a
 * dao interface. This definition assumes that interfaces are placed in the 
* "dao" package, and that implementation types are in sub-packages. 
*/ 
@Pointcut("execution(* com.xyz.someapp.dao.*.*(..))") 
public void dataAccessOperation() {} }

 

可以在任何地方引用需要引用定義好的切點表達式。例如,服務層的事務管理,如下:

<aop:config> 
<aop:advisor pointcut="com.xyz.someapp.SystemArchitecture.businessService()" advice-ref="tx-advice"/> 
</aop:config> 
<tx:advice id="tx-advice"> 
<tx:attributes> 
<tx:method name="*" propagation="REQUIRED"/> 
</tx:attributes> 
</tx:advice>

 

 

例如: Spring AOP 的用戶可以使用 execution  切點表達式,如:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)

下面展示一些常用的execution 表達的切點表達式

  • 執行任何的pulblic 方法

execution(public * *(..))

  • 執行任何的以 set 開頭的方法

execution(* set*(..))

  • 執行 AccountService 爲接口的任何方法

execution(* com.xyz.service.AccountService.*(..))

  • 在service 包下面的所有方法;

execution(* com.xyz.service.*.*(..))

  • 執行 service 包及其子包下面的所有方法;

execution(* com.xyz.service..*.*(..))

  • 任何在 service 包下面的切點

within(com.xyz.service.*)

  • 任何在service包及其子包下面的切點

within(com.xyz.service..*)

  • 任何實現AccountService 接口的切點

this(com.xyz.service.AccountService)

 

這裏target 表示實現AccountService 接口的所有鏈接點

target(com.xyz.service.AccountService)

獲取連接點一個參數,這個參數是運行時通過Serializable 實現的

args(java.io.Serializable)

獲取目標對象有註解@Transactional  的所有切點

@target(org.springframework.transaction.annotation.Transactional)

聲明的對象類型中含有註解  @Transactional 的所有切點

@within(org.springframework.transaction.annotation.Transactional)

在執行的方法有添加  @Transactional 註解的所有切點

@annotation(org.springframework.transaction.annotation.Transactional)

運行的時候有一個參數是 @Classified 註解的切點

@args(com.xyz.security.Classified)

有一個spring bean 名字爲 tradeService 的連接點

bean(tradeService)

Spring bean 匹配 *Service 通識符的bean的連接點

bean(*Service)

 

聲明通知

 

Before Advice

前置通知

聲明一個切點的前置通知可以使用 @Before 註解如下:

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;



@Aspect

public class BeforeExample {



@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")

public void doAccessCheck() {

// ...

}



}

如果是使用切點表達式,我們要重寫前面的示例:

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;



@Aspect

public class BeforeExample {



@Before("execution(* com.xyz.myapp.dao.*.*(..))")

public void doAccessCheck() {

// ...

}



}

 

返回結果後通知

返回結果通知通常是用來匹配一個方法正常結束後執行,可以通過@AfterReturning 註解來實現:


import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.AfterReturning;



@Aspect

public class AfterReturningExample {



@AfterReturning("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")

public void doAccessCheck() {

// ...

}



}

 

有時,我們需要訪問通知消息體的返回值。可以用下面的這個 @AfterReturning 這個註解方式 綁定返回值來獲取訪問權限。具體如下:

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.AfterReturning;



@Aspect

public class AfterReturningExample {



@AfterReturning(

pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",

returning="retVal")

public void doAccessCheck(Object retVal) {

// ...

}

}

 

異常通知:

當前匹配的一個方法執行拋出異常後退出時,執行異常通知 。可以用 @AfterThrowing  註解的方式來聲明如下:


import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;

@Aspect public class AfterThrowingExample {    
             
     @AfterThrowing("com.xyz.myapp.SystemArchitecture.dataAccessOperation()") 
     public void doRecoveryActions() {
         // ... 
    } 
}

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