Spring-AOP 流程切面

  • 概述
  • 实例
  • 总结

概述

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


实例

代码已托管到Github—> https://github.com/yangshangwei/SpringMaster

Spring-AOP 流程切面_第1张图片

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配置一个流程切面来完成这一需求


<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

Spring-AOP 流程切面_第2张图片

两个构造函数:

  • 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的两个方法都织入了增强


总结

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

你可能感兴趣的:(【Spring-AOP】,Spring-AOP基础手札,aop,流程切面)