通过上面几篇文章我们发现,实例中的定义的切面仅有一个切点,有的时候,一个切点可能难以描述目标连接点的信息。
上篇博文 Spring-AOP 流程切面的例子,如果我们希望由WaiterDelegate#service方法发起调用并且被调用的方法是Waiter#greetTo才织入增强,那么这个切点就是复合切点,因为它有两个单独的切点共同确定。
当然,我们可以只通过一个切点来描述同时满足上述两个匹配条件的连接点,但是更好的方式是使用Spring提供的ComposalbePointcut把两个切点组合起来,通过切点的符合运行算表示。 ComposalbePointcut可以将多个切点以并集或者交集的方式组合起来,提供切点之间复合运算的功能。
ComposablePointcut本身也是一个切点,它实现了Pointcut接口,
ComposablePointcut没有提供直接对两个切点机型并集交集的运算的方法,如果需要对连个切点进行叫交集并集运算,可以使用Spring提供的 org.springframework.aop.support.Pointcuts工具类,改工具类提供两个非常友好的静态方法
代码已托管到Github—> https://github.com/yangshangwei/SpringMaster
package com.xgj.aop.spring.advisor.ComposablePointcut;
public class Waiter {
public void greetTo(String name) {
System.out.println("Waiter Greet To " + name);
}
public void serverTo(String name) {
System.out.println("Waiter Server To " + name);
}
}
package com.xgj.aop.spring.advisor.ComposablePointcut;
public class WaiterDelegate {
private Waiter waiter;
public void setWaiter(Waiter waiter) {
this.waiter = waiter;
}
/**
*
*
* @Title: service
*
* @Description: waiter类中方法的调用,通过该方法发起
*
* @param name
*
* @return: void
*/
public void service(String name) {
waiter.greetTo(name);
waiter.serverTo(name);
}
}
前置增强
package com.xgj.aop.spring.advisor.ComposablePointcut;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class GreetingBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
// 输出切点
System.out.println("Pointcut:" + target.getClass().getName() + "."
+ method.getName());
String clientName = (String) args[0];
System.out.println("How are you " + clientName + " ?");
}
}
通过ComposablePointcut创建一个流程切点和方法名切点的相交切点
package com.xgj.aop.spring.advisor.ComposablePointcut;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.ComposablePointcut;
import org.springframework.aop.support.ControlFlowPointcut;
import org.springframework.aop.support.NameMatchMethodPointcut;
public class GreetingComposablePointcut {
public Pointcut getIntersectionPointcut() {
// 创建一个复合切点
ComposablePointcut composablePointcut = new ComposablePointcut();
// 创建一个流程切点
Pointcut controlFlowPointcut = new ControlFlowPointcut(
WaiterDelegate.class, "service");
// 创建一个方法名切点
NameMatchMethodPointcut nameMatchMethodPointcut = new NameMatchMethodPointcut();
nameMatchMethodPointcut.addMethodName("greetTo");
// 将两个切点进行交集操作
return composablePointcut.intersection(controlFlowPointcut)
.intersection((Pointcut) nameMatchMethodPointcut);
}
}
通过GreetingComposablePointcut#intersectionPointcut方法即可得到一个相交的复合切点,配置复合切点的切面和配置其他切点一样,如下所示
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="waiterTarget" class="com.xgj.aop.spring.advisor.ComposablePointcut.Waiter"/>
<bean id="greetingComposablePointcut" class="com.xgj.aop.spring.advisor.ComposablePointcut.GreetingComposablePointcut"/>
<bean id="greetingBeforeAdvice" class="com.xgj.aop.spring.advisor.ComposablePointcut.GreetingBeforeAdvice"/>
<bean id="composableAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"
p:pointcut="#{greetingComposablePointcut.intersectionPointcut}"
p:advice-ref="greetingBeforeAdvice"/>
<bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interceptorNames="composableAdvisor"
p:target-ref="waiterTarget"
p:proxyTargetClass="true"/>
beans>
测试类
package com.xgj.aop.spring.advisor.ComposablePointcut;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class IntroductionAdvisorTest {
@Test
public void test() {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"classpath:com/xgj/aop/spring/advisor/ComposablePointcut/conf-composablePointcut.xml");
Waiter waiter = ctx.getBean("waiter", Waiter.class);
waiter.greetTo("XiaoGongJiang");
waiter.serverTo("XiaoGongJiang");
WaiterDelegate waiterDelegate = new WaiterDelegate();
waiterDelegate.setWaiter(waiter);
waiterDelegate.service("XiaoGongJiang");
}
}
运行结果
2017-08-20 18:24:14,593 INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@eb6dcf9: startup date [Sun Aug 20 18:24:14 BOT 2017]; root of context hierarchy
2017-08-20 18:24:14,694 INFO [main] (XmlBeanDefinitionReader.java:317) - Loading XML bean definitions from class path resource [com/xgj/aop/spring/advisor/ComposablePointcut/conf-composablePointcut.xml]
Waiter Greet To XiaoGongJiang
Waiter Server To XiaoGongJiang
Pointcut:com.xgj.aop.spring.advisor.ComposablePointcut.Waiter.greetTo
How are you XiaoGongJiang ?
Waiter Greet To XiaoGongJiang
Waiter Server To XiaoGongJiang
通过输出信息可以看出,只有通过WaiterDelegate#service方法调用的Waiter#greetTo才织入了增强,这正是复合交集切点所描述的连接点