Spring-AOP 流程切面

来源:互联网 发布:xp打开关闭windows功能 编辑:程序博客网 时间:2024/05/23 14:20

  • 概述
  • 实例
  • 总结

概述

Spring的流程切面由DefaultPointcutAdvisorControlFlowPointcut实现。 流程切点代表由某个方法直接或者间接发起调用的其他方法。


实例

代码已托管到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 hierarchy2017-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 XiaoGongJiangWaiter Server To XiaoGongJiangPointcut:com.xgj.aop.spring.advisor.ControlFlowAdvisor.Waiter.greetToHow are you XiaoGongJiang ?Waiter Greet To XiaoGongJiangPointcut:com.xgj.aop.spring.advisor.ControlFlowAdvisor.Waiter.serverToHow are you XiaoGongJiang ?Waiter Server To XiaoGongJiang

我们在测试类中直接调用了greetTo和serverTo,此时增强并没有起作用,
我们通过WaiterDelegate的service调用Waiter中的greetTo和serverTo,,可以看到Waiter的两个方法都织入了增强


总结

流程切面和动态切面从某种城都说说可以算是一类切面,因为二者都需要在运行期判断动态的环境。 对于流程切面来讲,代理对象那个在每次调用目标类方法时,都需要判断方法调用堆栈中是否有满足流程切点要求的方法,和动态切面一样,对性能的影响很大.