introduction和advice比较
- introduction: 用于给目标引入新的接口,比如锁,状态功能时.生成一个mix-in的接口
- advice: 只是在原有接口的基础上增加附加内容
introduction
通过IntroductionInterceptor接口实现
- 实现一个introduction需要三个内容:
- 将要添加的新接口的定义
- 该新接口的实现,在实现的class中,必须实现Spring的IntroductionInterceptor接口
- IntroductionAdvisor接口的实现
public interface IntroductionInterceptor extends MethodInterceptor { /* * 此方法用于判断该introduction实现是否实现了intf接口类 * 所有对inf接口的调用方法都会转发给incoke方法,由invoke方法完成相应的任务 * * @param intf 接口类 * @return boolean 该introduction实现是否实现的接口类 */ boolean implementsInterface(Class intf); // invoke()方法来源于MethodInterceptor invoke(MethodInvocation invocation); }
- 示例: 添加一个aduitable功能
1.添加新的接口定义:
/**
* 1. auditable接口定义
*/
public interface Auditable {
void setLastModifiedDate(Date date);
Date getLastModifiedDate();
}
2.该新的接口的实现,必须实现Spring的IntroductionIntercepter:
/**
* 2. auditable接口的实现,同时要实现IntroductionIntercepter接口
*/
public class AuditableMixin implements IntroductionInterceptor, Aduitable {
/*
* 实现IntroductionInterceptor接口中的implementsInterface接口
*/
public boolean implementsInterface(Class intf) {
// AuditableMixin实现了Auditable类的功能
return intf.isAssignableFrom(Auditable.class);
}
public Object invoke(MethodInvocation m) throws Throwable {
/*
* 对invoke中的参数m进行判断,当前的调用是否在implementsInterface范围内
* 即当前的调用是否是auditable接口中的方法
*/
if (implementsInterface(m.getMethod().getDeclaringClass())) {
/*
* 调用引入的方法,来源于auditable接口,这样就可以给target添加新的auditable接口
* this就是对象本身
*/
return m.getMethod().invoke(this, m.getArguments());
} else {
// 调用其余方法
return m.proceed()
}
}
// 实现auditable接口
private Date lastModifiedDate;
public Date getLastModifiedDate() {
return lastModifiedDate;
}
public void setLastModifiedDate(Date lastModifiedDate) {
this.latsModifiedDate = lastModifiedDate;
}
}
通过DelegatingIntroductionInterceptor接口实现
- introduction除了直接实现IntroductionInterceptor接口外,还可以通过继承DelegatingIntroductionInterceptor类实现
- DelegatingIntroductionInterceptor默认实现了IntroductionInterceptor接口中的implementsInterface和invoke两个方法,仅仅需要自定义实现auditable接口
- 示例: 通过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;
}
}
Introduction总结
- 上述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;
}
/**
* 修改invoke方法
*/
public Object invoke(MethodInvocation m) throws Throwable {
String name = mi.getMethod().getName();
/*
* 如果已经是immutable,就不可以调用setXxx()方法
* 这样就改变了Target的行为,而不仅仅是添加行为
*/
if (immutable && name.indexOf("set") == 0) {
throw new IllegalModificationException();
}
return super.invoke(mi);
}
}
Spring中Introduction
- Spring中的Introduction需要有Advisor: IntroductionAdvisor
-
Spring中使用Introduction的注意点:
- Spring中使用的是动态AOP, 并没有像AspectJ使用静态的代码编译的方式生成AOP代码
- 因此只有从Spring的BeanFactory中得到的Introduction Bean才会被introduced
- 直接在代码中new出来的target对象则不具有Introduction功能
- 可以使用一个Factory来封装对Introduction的创建