自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Spring AOP之通知Advice API詳細(xì)介紹及使用

開發(fā) 架構(gòu)
最常使用的是每類Advice。它適用于一般的Advice,例如事務(wù)Advisors。這些不依賴于代理對(duì)象的狀態(tài)或添加新?tīng)顟B(tài)。它們只是對(duì)方法和參數(shù)起作用。

Advice生命周期

每個(gè)Advice都是一個(gè)Bean。Advice實(shí)例可以在所有Advisor之間共享,也可以對(duì)每個(gè)Advisor對(duì)象都是唯一的。這對(duì)應(yīng)于每個(gè)類或每個(gè)實(shí)例的Advice。

最常使用的是每類Advice。它適用于一般的Advice,例如事務(wù)Advisors。這些不依賴于代理對(duì)象的狀態(tài)或添加新?tīng)顟B(tài)。它們只是對(duì)方法和參數(shù)起作用。

每個(gè)實(shí)例Advice適用于引入,以支持mixin。在這種情況下,通知將狀態(tài)添加到代理對(duì)象。

你可以在同一個(gè)AOP代理中混合使用共享通知和每個(gè)實(shí)例通知。

Advice類型

Spring提供了幾種通知類型,并且可以擴(kuò)展以支持任意通知類型。

  • 攔截環(huán)繞通知

Spring中最基本的通知類型是圍繞通知的攔截。

Spring與AOP Alliance接口兼容,支持使用方法攔截的環(huán)繞通知。實(shí)現(xiàn)MethodInterceptor和around advice的類還應(yīng)該實(shí)現(xiàn)以下接口:

public interface MethodInterceptor extends  org.aopalliance.intercept.Interceptor {

Object invoke(MethodInvocation invocation) throws Throwable;
}

invoke()方法的MethodInvocation參數(shù)公開了被調(diào)用的方法、目標(biāo)連接點(diǎn)、AOP代理和方法的參數(shù)。invoke()方法應(yīng)該返回調(diào)用的結(jié)果:連接點(diǎn)的返回值。

面的例子展示了一個(gè)簡(jiǎn)單的MethodInterceptor實(shí)現(xiàn):

public class DebugInterceptor implements MethodInterceptor {

public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Before: invocation=[" + invocation + "]");
Object rval = invocation.proceed();
System.out.println("Invocation returned");
return rval;
}
}

注意:MethodInvocation中對(duì)proceed()方法的調(diào)用。這將沿著攔截器鏈向下直至連接點(diǎn)。大多數(shù)攔截器調(diào)用此方法并返回其返回值。然而,MethodInterceptor和任何around通知一樣,可以返回不同的值或拋出異常,而不是調(diào)用proceed方法。然而,如果沒(méi)有充分的理由,你不會(huì)想要這樣做。

MethodInterceptor實(shí)現(xiàn)提供了與其他遵循AOP聯(lián)盟的AOP實(shí)現(xiàn)的互操作性。雖然使用最具體的通知類型有好處,但如果你可能想在另一個(gè)AOP框架中運(yùn)行方面,請(qǐng)堅(jiān)持使用MethodInterceptor。注意,切入點(diǎn)目前不能在框架之間互操作,而且AOP聯(lián)盟目前不定義切入點(diǎn)接口。

  • 前置通知

一個(gè)簡(jiǎn)單的Advice類型是事前Adivce。它不需要MethodInvocation對(duì)象,因?yàn)樗辉谶M(jìn)入方法之前被調(diào)用。

before通知的主要優(yōu)點(diǎn)是不需要調(diào)用proceed()方法,因此不可能在無(wú)意中無(wú)法繼續(xù)執(zhí)行攔截器鏈。

public interface MethodBeforeAdvice extends BeforeAdvice {

void before(Method m, Object[] args, Object target) throws Throwable;
}

注意:返回類型是void。Before通知可以在連接點(diǎn)運(yùn)行之前插入自定義行為,但不能更改返回值。如果before通知拋出異常,它將停止攔截器鏈的進(jìn)一步執(zhí)行。異常在攔截器鏈中向上傳播。如果未檢查或在被調(diào)用方法的簽名上,它將直接傳遞給客戶端。否則,它將被AOP代理包裝在未檢異常中。

下面的例子展示了Spring中的before通知,它統(tǒng)計(jì)了所有的方法調(diào)用:

public class CountingBeforeAdvice implements MethodBeforeAdvice {

private int count;

public void before(Method m, Object[] args, Object target) throws Throwable {
++count;
}

public int getCount(){
return count;
}
}
  • 異常通知

如果連接點(diǎn)拋出異常,則在連接點(diǎn)返回后調(diào)用Throws通知。Spring提供了類型化異常通知。注意,這意味著org.springframework.aop.ThrowsAdvice接口不包含任何方法。它是一個(gè)標(biāo)記接口,標(biāo)識(shí)給定對(duì)象實(shí)現(xiàn)了一個(gè)或多個(gè)類型化throws通知方法。格式如下:

afterThrowing([Method, args, target], subclassOfThrowable)

Method,args,target3個(gè)參數(shù)是可選的。

public class BusinessThrowsAdvice implements ThrowsAdvice {

public void afterThrowing(BusinessException ex) throws Throwable {
// ...
}
}

下一個(gè)示例聲明了4個(gè)參數(shù),因此它可以訪問(wèn)被調(diào)用的方法、方法參數(shù)和目標(biāo)對(duì)象。如果拋出ServletException,將調(diào)用以下Advice:

public class ControllerAdviceWithArguments implements ThrowsAdvice {

public void afterThrowing(Method m, Object[] args, Object target, MethodArgumentNotValidException ex){
// ...
}
}

在一個(gè)異常通知類中定義多個(gè)不同異常的處理

public static class CombinedThrowsAdvice implements ThrowsAdvice {
public void afterThrowing(BusinessException ex) throws Throwable {
// ...
}
public void afterThrowing(Method m, Object[] args, Object target, MethodArgumentNotValidException ex){
// ...
}
}
  • 后置通知

Spring中的后置通知必須實(shí)現(xiàn)org.springframework.aop.AfterReturningAdvice接口,如下:

public interface AfterReturningAdvice extends Advice {

void afterReturning(Object returnValue, Method m, Object[] args, Object target) throws Throwable;
}

返回通知可以訪問(wèn)返回值(它不能修改)、被調(diào)用的方法、方法的參數(shù)和目標(biāo)。

public class CountingAfterReturningAdvice implements AfterReturningAdvice {

private int count;

public void afterReturning(Object returnValue, Method m, Object[] args, Object target) throws Throwable {
++count;
}

public int getCount(){
return count;
}
}

如果它拋出異常,它將被拋出攔截器鏈,而不是返回值。

  • 引介通知

Spring將引介通知視為一種特殊的攔截通知。

Introduction需要一個(gè)IntroductionAdvisor和一個(gè)IntroductionInterceptor實(shí)現(xiàn)以下接口:

public interface IntroductionInterceptor extends MethodInterceptor {

boolean implementsInterface(Class intf);
}

從AOP Alliance方法攔截器接口繼承的invoke()方法必須實(shí)現(xiàn)引入。也就是說(shuō),如果被調(diào)用的方法在引入的接口上,則引入攔截器負(fù)責(zé)處理方法調(diào)用—它不能調(diào)用proceed()。

引介通知不能與任何切入點(diǎn)一起使用,因?yàn)樗贿m用于類級(jí)別,而不是方法級(jí)別。你只能在 IntroductionAdvisor中使用介紹建議,它有以下方法:

public interface IntroductionAdvisor extends Advisor, IntroductionInfo {

ClassFilter getClassFilter();

void validateInterfaces() throws IllegalArgumentException;
}

public interface IntroductionInfo {

Class<?>[] getInterfaces();
}

沒(méi)有MethodMatcher,因此也沒(méi)有與引介通知相關(guān)聯(lián)的切入點(diǎn)。只有類過(guò)濾。

getInterfaces()方法返回這個(gè)Advisor引入的接口。

validateInterfaces()方法在內(nèi)部使用,以查看引入的接口是否可以由配置的IntroductionInterceptor實(shí)現(xiàn)。下面直接給出示例,該示例的作用就是使某個(gè)類不具備某個(gè)接口能力時(shí)動(dòng)態(tài)給予該接口的能力:

接口:

public interface CountDAO {

public void count() ;
}

這里的引介攔截器必須實(shí)現(xiàn)我們期望的一個(gè)接口:

public class CustomIntroductionInterceptor implements IntroductionInterceptor, CountDAO {

@Override
public void count(){
System.out.println("訂單統(tǒng)計(jì)...") ;
}

@Override
public boolean implementsInterface(Class<?> intf){
return CountDAO.class.isAssignableFrom(intf) ;
}

@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
if (implementsInterface(invocation.getMethod().getDeclaringClass())) {
System.out.println("我是Introduction增強(qiáng)..." + "Class: " + invocation.getMethod().getDeclaringClass() + ", method: " + invocation.getMethod().getName()) ;
// 實(shí)際調(diào)用的就是當(dāng)前Advice實(shí)現(xiàn)的CountDAO#count方法。
return invocation.getMethod().invoke(this, invocation.getArguments()) ;
}
return invocation.proceed() ;
}

}

創(chuàng)建代理處理器:

@Component
public class OrderProxyCreater extends AbstractAutoProxyCreator {

@Override
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName,
TargetSource customTargetSource) throws BeansException {
return new Object[] {new DefaultIntroductionAdvisor(new CustomIntroductionInterceptor(), CountDAO.class)} ;
}

// 判斷只要不是OrderDAO類型的都進(jìn)行跳過(guò)(這里只代理是OrderDAO類型的Bean)
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName){
return !OrderDAO.class.isAssignableFrom(beanClass) ;
}
}

OrderDAO實(shí)現(xiàn),該DAO并沒(méi)有實(shí)現(xiàn)CountDAO:

@Service
public class OrderDAOImpl implements OrderDAO {

@Override
public void save(){
System.out.println("保存訂單...") ;
}

@Override
public void query(){
System.out.println("查詢訂單...") ;
}
}

測(cè)試:

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext("com.pack.aop") ;
ctx.registerShutdownHook();
OrderDAO persondao = ctx.getBean(OrderDAO.class) ;
persondao.save() ;
Object obj = ctx.getBean("orderDAOImpl") ;
if (obj instanceof CountDAO) {
CountDAO cdao = (CountDAO) obj ;
cdao.count() ;
}

運(yùn)行結(jié)果:

保存訂單...
我是Introduction增強(qiáng)...Class: interface com.pack.aop.CountDAO, method: count

從運(yùn)行結(jié)果看到OrderDAO具備了CountDAO接口能力,而具體實(shí)現(xiàn)CountDAO是我們的引介攔截器上實(shí)現(xiàn)的。

責(zé)任編輯:姜華 來(lái)源: 今日頭條
相關(guān)推薦

2023-01-30 11:35:14

SpringJava

2009-09-29 10:00:40

Spring AOP框

2022-06-07 07:58:45

SpringSpring AOP

2009-06-19 14:49:43

Spring框架

2016-07-14 15:09:29

華為

2010-06-02 09:01:20

Linux core

2022-06-08 08:04:28

Springservicerepository

2009-06-18 09:47:14

Spring的核心

2009-08-07 16:10:20

C#調(diào)用API

2009-06-19 11:09:27

Spring AOP

2009-06-17 14:57:11

Spring事務(wù)管理

2012-04-27 10:55:45

JavaExcelAPI

2021-03-01 23:26:41

日志Spring BootAOP

2023-11-16 09:01:37

Hadoop數(shù)據(jù)庫(kù)

2021-05-06 18:17:52

SpringAOP理解

2021-10-27 11:33:31

數(shù)據(jù)倉(cāng)庫(kù)架構(gòu)

2011-07-13 11:12:43

C++MFC

2011-06-30 14:04:41

Qt IP地址 接口

2009-08-21 15:16:23

C#使用指針
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)