SpringAOP中切點的高級使用
一、使用控制流切入點(ControlFlowPointcut)
什么是控制流切入點呢?看下面的代碼(為了方便,就寫進了一個公共類)
class Cat {
public void talk() {
System.out.println("I am a cat");
}
public void play() {
System.out.println("I am palying");
}
}
class BlackCat {
public void sleep(Cat cat) {
cat.play();
System.out.println("I am a blackCat , I am sleeping");
}
}
/**
* 創建前置通知類
*/
class BeforeAdvice implements MethodBeforeAdvice{
@Override
public void before(Method method, Object[] objects, @Nullable Object o) throws Throwable {
System.out.println("這個方法被通知了"+method);
}
}
- 需求:我們要給Cat的play()方法進行通知,但是呢,並不是說在調用play()方法的任何時候都通知, 只要在blackCat的sleep()方法中調用play()方法時才通知,也就是說:
public static void main(String[] args) {
Cat cat = new Cat();
cat.play();//這個調用不會被通知
BlackCat blackCat = new BlackCat();
blackCat.sleep(cat);//這個方法中調用的paly方法才會被通知
}
創建一個ControlFlowPointcut的切入點
public static void main(String[] args) {
// Cat cat = new Cat();
// cat.play();//這個調用不會被通知
//
// BlackCat blackCat = new BlackCat();
// blackCat.sleep(cat);//這個方法中調用的paly方法才會被通知
Cat target = new Cat();
//第一個參數是當前就是的執行要被通知的方法的類,第二個就是的執行要被通知的方法的方法名
Pointcut pc = new ControlFlowPointcut(BlackCat.class, "sleep");
Advisor advisor = new DefaultPointcutAdvisor(pc, new BeforeAdvice());
ProxyFactory proxy = new ProxyFactory();
proxy.setTarget(target);
proxy.addAdvisor(advisor);
Cat proxyCat = (Cat) proxy.getProxy();
proxyCat.play();//這個方法不會被通知
System.out.println("----------------");
BlackCat blackCat = new BlackCat();
blackCat.sleep(proxyCat);//這個方法中調用的paly方法才會被通知
}
二、使用組合切入點(ComposablePointcut)
所謂組合切入點就是利用邏輯關系(or 和 and)來對切入點進行組合,比如上一文中說過的那幾種切入點,使用邏輯關系寫在一起就可以了。但是並不是直接和切入點來組合,而是組合切入點中的
ClassFilter和MethodMatcher
(為什么是這樣?在這篇文章看一下Pointcut類的源碼,就明白了)
-
用法:
ComposablePointcut的union()表示“或”
ComposablePointcut的intersection()表示“和” -
先定義三個MethodMatcher類
/**
* 匹配sleep方法名
*/
class SleepMethodMatcher extends StaticMethodMatcher{
@Override
public boolean matches(Method method, Class<?> aClass) {
return method.getName().equals("sleep");
}
}
/**
* 匹配s開頭
*/
class SStartMethodMatcher extends StaticMethodMatcher{
@Override
public boolean matches(Method method, Class<?> aClass) {
return method.getName().startsWith("s");
}
}
/**
* 匹配k結尾
*/
class KEndMethodMatcher extends StaticMethodMatcher{
@Override
public boolean matches(Method method, Class<?> aClass) {
return method.getName().endsWith("k");
}
}
- 創建切入點
/**
* 創建前置通知類
*/
class BeforeAdviceDemo implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, @Nullable Object o) throws Throwable {
System.out.println("這個方法被通知了" + method);
}
}
- 測試類
public static void main(String[] args) {
Cat target = new Cat();
//這個構造方法要傳入的是一個classFilter和methodMatcher實例
ComposablePointcut pc = new ComposablePointcut(ClassFilter.TRUE, new KEndMethodMatcher());
// pc.union(new SStartMethodMatcher());//匹配s開頭的方法,和上邊的切點是或的關系
// pc.intersection(new SleepMethodMatcher()); //匹配sleep方法,和上邊切點是和的關系
Advisor advisor = new DefaultPointcutAdvisor(pc,new BeforeAdviceDemo());
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
proxyFactory.addAdvisor(advisor);
Cat cat = (Cat) proxyFactory.getProxy();
cat.talk();
}
上邊的這個ClassFilter.TRUE 和下邊代碼其實是一樣的,意思就是返回的classFilter為true,也就是匹配所有類
new ClassFilter() {
@Override
public boolean matches(Class<?> aClass) {
return true;
}
}