欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring-AOP 流程切面

程序员文章站 2024-03-19 16:24:52
...

概述

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


实例

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

Spring-AOP 流程切面

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

Spring-AOP 流程切面

两个构造函数:

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


总结

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

相关标签: aop 流程切面