天天看点

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);      

继续阅读