Spring-AOP 流程切面
概述
Spring的流程切面由DefaultPointcutAdvisor和ControlFlowPointcut实现。 流程切点代表由某个方法直接或者间接发起调用的其他方法。
实例
代码已托管到Github—> https://github.com/yangshangwei/SpringMaster
package com.xgj.aop.spring.advisor.ControlFlowAdvisor;
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);
}
}
我们通过一个WaiterDelegate类调用Waiter中的所有方法
package com.xgj.aop.spring.advisor.ControlFlowAdvisor;
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);
}
}
我们希望所有由WaiterDelegate .service方法发起调用的其他方法都织入GreetingBeforeAdvice前置增强,就必须使用流程切面来完成了。
编写增强
package com.xgj.aop.spring.advisor.ControlFlowAdvisor;
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 + " ?");
}
}
下面使用DefaultPointcutAdvisor配置一个流程切面来完成这一需求
<?xml version="1.0" encoding="UTF-8"?>
<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.ControlFlowAdvisor.Waiter"/>
<!-- 增强 -->
<bean id="greetingBeforeAdvice" class="com.xgj.aop.spring.advisor.ControlFlowAdvisor.GreetingBeforeAdvice"/>
<!-- 流程切点 指定流程切点的类 和 流程切点的方法-->
<bean id="controlFlowPointcut" class="org.springframework.aop.support.ControlFlowPointcut">
<constructor-arg type="java.lang.Class" value="com.xgj.aop.spring.advisor.ControlFlowAdvisor.WaiterDelegate"/>
<constructor-arg type="java.lang.String" value="service"/>
</bean>
<!-- 切面 -->
<bean id="controlFlowAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"
p:pointcut-ref="controlFlowPointcut"
p:advice-ref="greetingBeforeAdvice"/>
<!-- 代理类 -->
<bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interceptorNames="controlFlowAdvisor"
p:target-ref="waiterTarget"
p:proxyTargetClass="true"/>
</beans>
我们来看下ControlFlowPointcut
两个构造函数:
ControlFlowPointcut(Class<?> clazz)
指定一个类作为流程切点ControlFlowPointcut(Class<?> clazz, String methodName)
指定一个类和某一个方法作为流程切点
我们这里指定com.xgj.aop.spring.advisor.ControlFlowAdvisor.WaiterDelegate中的service()方法作为流程切点,表示所有通过该方法直接或者间接发起的调用匹配切点。
编写测试类
package com.xgj.aop.spring.advisor.ControlFlowAdvisor;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ControlFlowAdvisorTest {
@Test
public void test() {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"classpath:com/xgj/aop/spring/advisor/ControlFlowAdvisor/conf-controlFlowAdvisor.xml");
Waiter waiter = ctx.getBean("waiter", Waiter.class);
waiter.greetTo("XiaoGongJiang");
waiter.serverTo("XiaoGongJiang");
System.out.println("\n");
WaiterDelegate waiterDelegate = new WaiterDelegate();
waiterDelegate.setWaiter(waiter);
waiterDelegate.service("XiaoGongJiang");
}
}
运行结果:
2017-08-20 03:36:49,907 INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@76566fb: startup date [Sun Aug 20 03:36:49 BOT 2017]; root of context hierarchy
2017-08-20 03:36:50,020 INFO [main] (XmlBeanDefinitionReader.java:317) - Loading XML bean definitions from class path resource [com/xgj/aop/spring/advisor/ControlFlowAdvisor/conf-controlFlowAdvisor.xml]
Waiter Greet To XiaoGongJiang
Waiter Server To XiaoGongJiang
Pointcut:com.xgj.aop.spring.advisor.ControlFlowAdvisor.Waiter.greetTo
How are you XiaoGongJiang ?
Waiter Greet To XiaoGongJiang
Pointcut:com.xgj.aop.spring.advisor.ControlFlowAdvisor.Waiter.serverTo
How are you XiaoGongJiang ?
Waiter Server To XiaoGongJiang
我们在测试类中直接调用了greetTo和serverTo,此时增强并没有起作用,
我们通过WaiterDelegate的service调用Waiter中的greetTo和serverTo,,可以看到Waiter的两个方法都织入了增强
总结
流程切面和动态切面从某种城都说说可以算是一类切面,因为二者都需要在运行期判断动态的环境。 对于流程切面来讲,代理对象那个在每次调用目标类方法时,都需要判断方法调用堆栈中是否有满足流程切点要求的方法,和动态切面一样,对性能的影响很大.
上一篇: 什么是消息队列 RocketMQ?