在前面四个例子中只要实现一个Advice然后调用ProxyFactoryaddAdvice()方法为代理设定通知不用设置切入点从代理对上调用的方法就被通知到了其原因就在于执行addAdvice()方法时ProxyFactory会将Advice对象委派给addAdvistor()方法后台会自动创建一个DefaultPointcutAdvistor实例并将Advice加入其中而默认的DefaultPointcutAdvistor会将切入点设为所有的方法
假如我们不想通过代理来执行某些方法也就是说在执行某些方法的时候不通知这时候该如何实现呢?
Spring提供一系列接口来实现这个目标最主要的接口如下
implements orgspringframeworkaopPointcut
orgspringframeworkaopClassFilter
orgspringframeworkaopMethodMatcher
下面看看几个关键接口的定义
切入点(Pointcut)
/**
* 切入点
*/
public interface Pointcut {
//切入点的一个单例
public static final Pointcut TRUE = TruePointcutINSTANCE;
//类过滤器
public ClassFilter getClassFilter();
//方法过滤器
public MethodMatcher getMethodMatcher();
}
/**
* 类过滤器
*/
public interface ClassFilter {
//类过滤器单例
public static final ClassFilter TRUE = TrueClassFilterINSTANCE;
//类匹配方法
public boolean matches(Class class);
}
/**
* 方法过滤器
*/
public interface MethodMatcher {
//方法过滤器单例
public static final MethodMatcher TRUE = TrueMethodMatcherINSTANCE;
//静态方法匹配方法
public boolean matches(Method method Class class);
//判断静态还是动态匹配返回true动态匹配false静态匹配
public boolean isRuntime();
//对象(动态)匹配方法
public boolean matches(Method method Class class Object aobj[]);
}
通知者(Advisor)
/**
* 通知者接口
*/
public interface Advisor {
//切面是否为per instance
public boolean isPerInstance();
//获取切面上的通知
public Advice getAdvice();
}
/**
* 通知者子接口Spring中标准的切面都应该实现此接口
*/
public PointcutAdvisor extends Advisor {
//获取通知者的切点
public Pointcut getPointcut();
}
为了看的明白还是回顾一下框架图
还有很多接口和类没有画出这里简要说明下
在orgspringframeworkaopsupport包下还有一些很重要的切点类是Spring定义好的几乎可以满足所用应用的需要
DynamicMethodMatcherPointcut
NameMatchMethodPointcut
PerlRegexpMethodPointcut
StaticMethodMatcherPointcut
JdkRegexpMethodPointcut
ControlFlowPointcut
ComposablePointcut
与这些切点对应还有一些切面类名字都是以PointcutAdvisor结尾
通过上面的原理图简单查看一下API就可以直到通过通知Advice和切点Pointcut可以生成通知者Advisor有了通知者有了目标对象就可以通过ProxyFactory生成代理对象
下面给个例子看看Spring如何通过切点来选取类和方法的并如通知所选取的方法
例子扩展StaticMethodMatcherPointcut实现静态切入点过滤
/**
* 业务组件BeanOne
*/
public class BeanOne {
public void foo() {
Systemoutprintln(BeanOne的foo()被调用!);
}
public void bar() {
Systemoutprintln(BeanOne的bar()被调用!);
}
}
/**
* 业务组件BeanTwo
*/
public class BeanTwo {
public void foo() {
Systemoutprintln(BeanTwo的foo()被调用!);
}
public void bar() {
Systemoutprintln(BeanTwo的bar()被调用!);
}
}
import orgaopallianceinterceptMethodInterceptor;
import orgaopallianceinterceptMethodInvocation;
/**
* 自定义通知Advice
*/
public class SimpleAdvice implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
Systemoutprintln(>> 业务方法调用前动作被代理调用目标方法是 + invocationgetMethod()getName());
Object retVal = invocationproceed();
Systemoutprintln(>> 业务方法调用结束后动作!);
return retVal;
}
}
import javalangreflectMethod;
import orgspringframeworkaopClassFilter;
import orgspringframeworkaopsupportStaticMethodMatcherPointcut;
/**
* 自定义静态切入点Pointcut
*/
public class SimpleStaticPointcut extends StaticMethodMatcherPointcut {
public boolean matches(Method method Class cls) {
//类方法名为foo时候匹配
Systemoutprintln(切入点方法匹配正在匹配+clsgetName()+的+methodgetName()+方法!);
return (fooequals(methodgetName()));
}
public ClassFilter getClassFilter() {
return new ClassFilter() {
public boolean matches(Class cls) {
Systemoutprintln(切入点类匹配正在匹配+clsgetName()+类!);
//BeanOne类匹配
return (cls == BeanOneclass);
}
};
}
}
import orgaopallianceaopAdvice;
import orgspringframeworkaopAdvisor;
import orgspringframeworkaopPointcut;
import orgspringframeworkaopframeworkProxyFactory;
import orgspringframeworkaopsupportDefaultPointcutAdvisor;
/**
* 客户端测试
*/
public class StaticPointcutExample {
public static void main(String[] args) {
//创建目标对象
BeanOne one = new BeanOne();
BeanTwo two = new BeanTwo();
//定义代理对象
BeanOne proxyOne;
BeanTwo proxyTwo;
//创建一个切入点
Pointcut pc = new SimpleStaticPointcut();
//创建一个通知
Advice advice = new SimpleAdvice();
//创建一个通知者(即通知和切入点的结合)
Advisor advisor = new DefaultPointcutAdvisor(pc advice);
//创建一个代理工厂
ProxyFactory pf = new ProxyFactory();
//将方面加入工厂
pfaddAdvisor(advisor);
//将目标加入工厂
pfsetTarget(one);
//获取代理对象产品
proxyOne = (BeanOne) pfgetProxy();//这个时候会进行匹配检查
//创建一个代理工厂
pf = new ProxyFactory();
pfaddAdvisor(advisor);
pfsetTarget(two);
proxyTwo = (BeanTwo) pfgetProxy();
/*
orgspringframeworkaopframeworkProxyFactory中
设置的代理目标一次仅能一个这点不要犯迷糊我查过源码了
*/
//从代理产品上调用目标方法
proxyOnefoo();
proxyTwofoo();
proxyOnebar();
proxyTwobar();
}
}
运行结果
Using JDK collections
切入点类匹配正在匹配comapressprospringchstaticpcBeanOne类!
切入点方法匹配正在匹配comapressprospringchstaticpcBeanOne的foo方法!
切入点类匹配正在匹配comapressprospringchstaticpcBeanOne类!
切入点方法匹配正在匹配comapressprospringchstaticpcBeanOne的bar方法!
切入点类匹配正在匹配comapressprospringchstaticpcBeanOne类!
切入点方法匹配正在匹配comapressprospringchstaticpcBeanOne的hashCode方法!
切入点类匹配正在匹配comapressprospringchstaticpcBeanOne类!
切入点方法匹配正在匹配comapressprospringchstaticpcBeanOne的toString方法!
切入点类匹配正在匹配comapressprospringchstaticpcBeanTwo类!
切入点类匹配正在匹配comapressprospringchstaticpcBeanTwo类!
切入点类匹配正在匹配comapressprospringchstaticpcBeanTwo类!
切入点类匹配正在匹配comapressprospringchstaticpcBeanTwo类!
切入点类匹配正在匹配comapressprospringchstaticpcBeanOne类!
切入点方法匹配正在匹配comapressprospringchstaticpcBeanOne的foo方法!
>> 业务方法调用前动作被代理调用目标方法是 foo
BeanOne的foo()被调用!
>> 业务方法调用结束后动作!
BeanTwo的foo()被调用!
BeanOne的bar()被调用!
BeanTwo的bar()被调用!
Process finished with exit code