`
qz小峰
  • 浏览: 14738 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
最近访客 更多访客>>
社区版块
存档分类
最新评论
  • sgzlove2007: 如果我要在我的JMX服务中加上一个用户名密码这样的连接限制的话 ...
    JMX

Introdcution Advice

阅读更多
Spring AOP中的Introduction:

正如前面已经提到的,Introduction和前面的四个advice是有很大的区别的,introduction用于给target引入新的接口(例如锁,状态等功能),生成一个mix-in的接口。而普通的advice只是在原有接口基础上增加附加内容。

在Spring中,完成一个introduction需要三个内容:1、将要添加的新接口的定义,2、该新接口的实现,在实现的class中,必须实现Spring的IntroductionInterceptor接口(Spring in action原文有误),3、IntroductionAdvisor接口的实现。
public interface IntroductionInterceptor extends MethodInterceptor {
  boolean implementsInterface(Class intf);
  Object invoke(MethodInvocation invocation) //此方法来源于MethodInterceptor
}

其中implementsInterface方法返回一个boolean值,此方法用于判断该introduction实现是否实现了某个接口――intf参数。所有对intf接口的调用都会转发给invoke方法,由invoke方法完成相应的任务。下面给出例子(给某个类添加是否auditable功能):

public interface Auditable {//1、auditable接口的定义
     void setLastModifiedDate(Date date);
     Date getLastModifiedDate();
}

public class AuditableMixin
implements IntroductionInterceptor, Auditable {//2、auditable接口的实现,同时要实现IntroductionInterceptor接口
public boolean implementsInterface(Class intf) {
      return intf.isAssignableFrom(Auditable.class);  // AuditableMixin实现了Auditable类的功能
}

public Object invoke(MethodInvocation m) throws Throwable {
     if (implementsInterface(m.getMethod().getDeclaringClass())) {//对invoke的参数m进行判断,当前的调用是否在implementsInterface范围内,即,当前的调用是否是auditable接口中的方法?
     return m.getMethod().invoke(this, m.getArguments());
//这里的this就是自己,调用引入的方法(属于auditable接口的方法),这样也就给target添加了新的auditable接口。
} else {
return m.proceed();//其他方法的调用。
}
}
private Date lastModifiedDate; //实现auditable接口。
public Date getLastModifiedDate() {
    return lastModifiedDate;
}
public void setLastModifiedDate(Date lastModifiedDate) {
     this.lastModifiedDate = lastModifiedDate
}
}

在Spring中,除了上面直接实现IntroductionInterceptor接口之外,还可以通过继承DelegatingIntroductionInterceptor类实现。其中DelegatingIntroductionInterceptor给出了IntroductionInterceptor接口中的两个方法(implementsInterface,invoke)的默认实现,你仅需要实现auditable接口即可。

通过跟踪Spring源代码可以发现:DelegatingIntroductionInterceptor的implementsInterface (在IntroductionInfoSupport类中)和invoke方法与上面的代码的形式基本一致。下面是利用DelegatingIntroductionInterceptor写出的AuditableMixin:

public class AuditableMixin extends DelegatingIntroductionInterceptor implements Auditable {
   private Date lastModifiedDate;
   public Date getLastModifiedDate() {
        return lastModifiedDate;
   }

public void setLastModifiedDate(Date lastModifiedDate) {
     this.lastModifiedDate = lastModifiedDate;
}     
}

    注意到一点:上面的两个AuditableMixin的实现都仅仅是给Target添加行为,但是未曾改变Target的原有行为(因为在invoke方法的实现中,还是会转发给Target)。如果需要改变Target的行为(例如给Target增加lock接口,一旦处于locked状态,那么再调用Target的方法就会出现异常),这就需要自己写代码修改invoke方法。

public class ImmutableMixin extends DelegatingIntroductionInterceptor implements Immutable {
   private boolean immutable;
   public void setImmutable(boolean immutable) {
        this.immutable = immutable;
}
public Object invoke(MethodInvocation mi) throws Throwable {
        String name = mi.getMethod().getName();
         if (immutable && name.indexOf("set") == 0) { //这里一旦已经是immutable了,那么就不可以调用setXXX方法了,这也就改变了Target的行为,而不是前面的仅增加接口。
throw new IllegalModificationException();
}
       return super.invoke(mi);
}
}



Spring中的Introduction需要有自己的advisor: IntroductionAdvisor
剩下的也就是和前面一样的xml文件的编写了。


Spring中使用Introduction需要注意的问题:
    由于Spring使用的是动态AOP,并没有象AspectJ使用静态的代码预编译的方式生成AOP代码,因此只有你从Spring的 BeanFactory中得到的Introduction Bean才会已经被introducted,而直接在代码中new出来的target对象则不具有Intorduction功能。你可以使用一个Factory,封装对Introduction的创建。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics