天天看點

Spring中的Advisor,Advice,Pointcut,Advised

        在Spring中,相關的api提供了對某類方法的攔截,也提供了對某些類的代理,以下是本人對spring參考手冊的了解,純屬一家之言。對方法的攔截通過定義配置Advisior,Advice,Pointcut而實作;通過Advised接口實作代理類的生成,以下分兩方面攔截者和代理類來闡述

I、攔截者

一、Spring中的Advisor,Advice,Point概述

1、Advisor:充當Advice和Pointcut的擴充卡,類似使用Aspect的@Aspect注解的類(前一章節所述)。一般有advice和pointcut屬性。

祖先接口為org.springframework.aop.Advisor,應用中可直接使用org.springframework.aop.support.DefaultPointcutAdvisor

2、Advice:用于定義攔截行為,祖先接口為org.aopalliance.aop.Advice,該接口隻是辨別接口,應用中可直接實作BeforeAdvice ,ThrowsAdvice,MethodInterceptor ,AfterReturningAdvice ,IntroductionInterceptor 等子接口

3、Pointcut:用于定義攔截目标集合,祖先接口為org.springframework.aop.Pointcut

二、Spring中的Advisor,Advice,Point的應用

1、編寫Advisor實作類

在此可直接使用org.springframework.aop.support.DefaultPointcutAdvisor

2、編寫Advice實作類

public class PlayAdvice implements MethodBeforeAdvice{

 public void before(Method method, Object[] args, Object target)

   throws Throwable {

  System.out.println("my before advice");

 // method.invoke(target, args); 如果再調用這句,則目标方法會執行多一次

 }

}

3、編寫Pointcut實作類

public class PlayPointcut implements Pointcut {

 public ClassFilter getClassFilter() {

  return new PlayClassFilter();

 }

 public MethodMatcher getMethodMatcher() {

  return new PlayMethodMatcher();

 }

}

//PlayClassFilter的定義

class PlayClassFilter implements ClassFilter {

 public boolean matches(Class clazz) {

  if(clazz.getSimpleName().equals("Play"))

   return true;

  return false;

 }

}

//PlayMethodMatcher的定義

class PlayMethodMatcher implements MethodMatcher {

 public boolean isRuntime() {

  return true;

 }

 public boolean matches(Method method, Class c) {

  if(c.getSimpleName().equals("Play")&&method.getName().contains("Service"))

   return true;

  return false;

 }

 public boolean matches(Method method, Class c, Object[] args) {

  if(c.getSimpleName().equals("Play")&&method.getName().contains("Service"))

   return true;

  return false;

 }

}

4、編寫目标類

public class Play {

  public void playService(String what){

  System.out.println("play "+what);

 }

}

5、在配置檔案中配置

<bean id="adviceBean" class="com.hss.sp.aop.PlayAdvice"/>

<bean id="pointcutBean" class="com.hss.sp.aop.PlayPointcut"/>

<bean id="playService" class="com.hss.sp.service.Play"/>

<bean

   class="org.springframework.aop.support.DefaultPointcutAdvisor">

   <property name="advice" ref="adviceBean"></property>

   <property name="pointcut" ref="pointcutBean"></property>

</bean>

6、測試,結果

 BeanFactory bf=new ClassPathXmlApplicationContext("applicationContext.xml");

  Play play=(Play)bf.getBean("playService");

  play.playService("pingpong");

輸出:

my before advice

play pingpong

II、代理者

      在Spring中建立了AOP代理之後,你能夠使用

org.springframework.aop.framework.Advised

接口對它們進行管理。 任何AOP代理都能夠被轉型為這個接口,不論它實作了哪些其它接口。這個接口包括下面的方法:

Advisor[] getAdvisors();
        
        void addAdvice(Advice advice) throws AopConfigException;
        
        void addAdvice(int pos, Advice advice) 
        throws AopConfigException;
        
        void addAdvisor(Advisor advisor) throws AopConfigException;
        
        void addAdvisor(int pos, Advisor advisor) throws AopConfigException;
        
        int indexOf(Advisor advisor);
        
        boolean removeAdvisor(Advisor advisor) throws AopConfigException;
        
        void removeAdvisor(int index) throws AopConfigException;
        
        boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException;
        
    boolean isFrozen();      

getAdvisors()

方法将為每個已經被加入工廠的通知器,攔截器或者其它通知類型傳回一個通知器。如果你曾經添加一個通知器,那麼所傳回的通知器将是你加入的對象。 如果你曾經加入一個攔截器或者其它通知類型,Spring将把它們包裝在一個通知器裡,後者使用一個永遠傳回true的切入點。是以如果你曾經加入一個

MethodInterceptor

, 傳回的通知器将是一個

DefaultPointcutAdvisor

,它可以傳回你加入的

MethodInterceptor

和一個比對所有類和方法的切入點。

addAdvisor()

方法可以用來添加任何通知器。通常儲存切入點和通知的通知器是

DefaultPointcutAdvisor

,它可以用于任何通知或切入點(但不包括引入類型)。

預設情況下,你可以加入或移除通知器或者攔截器甚至當代理已經被建立之後。唯一的限制是無法加入或者移除一個引入通知器,因為工廠中獲得的已有代理不能顯示接口的改變(你可以通過從工廠裡擷取一個新的代理來避免這個問題)。

下面是一個簡單的例子,它把一個AOP代理轉型為

Advised

接口,檢查并操作它的通知:

Advised advised = (Advised) myObject;
            Advisor[] advisors = advised.getAdvisors();
            int oldAdvisorCount = advisors.length;
            System.out.println(oldAdvisorCount + " advisors");
            
            // Add an advice like an interceptor without a pointcut
            // Will match all proxied methods
            // Can use for interceptors, before, after returning or throws advice
            advised.addAdvice(new DebugInterceptor());
            
            // Add selective advice using a pointcut
            advised.addAdvisor(new DefaultPointcutAdvisor(mySpecialPointcut, myAdvice));
            
            assertEquals("Added two advisors",
        oldAdvisorCount + 2, advised.getAdvisors().length);      

繼續閱讀