Spring-AOP 复合切点切面

简介: Spring-AOP 复合切点切面

概述


通过上面几篇文章我们发现,实例中的定义的切面仅有一个切点,有的时候,一个切点可能难以描述目标连接点的信息。


上篇博文 Spring-AOP 流程切面的例子,如果我们希望由WaiterDelegate#service方法发起调用并且被调用的方法是Waiter#greetTo才织入增强,那么这个切点就是复合切点,因为它有两个单独的切点共同确定。


当然,我们可以只通过一个切点来描述同时满足上述两个匹配条件的连接点,但是更好的方式是使用Spring提供的ComposalbePointcut把两个切点组合起来,通过切点的符合运行算表示。 ComposalbePointcut可以将多个切点以并集或者交集的方式组合起来,提供切点之间复合运算的功能。


ComposablePointcut源码


ComposablePointcut本身也是一个切点,它实现了Pointcut接口,


ComposablePointcut的构造函数


20170821055149423.jpg


public ComposablePointcut()


构造一个匹配所有类所有方法的复合切点


public ComposablePointcut(Pointcut pointcut)


构造出一个匹配特定切点的复合切点


public ComposablePointcut(ClassFilter classFilter)


构造一个匹配特定类所有方法的复合切点


public ComposablePointcut(MethodMatcher methodMatcher)


构造出一个匹配所有类特定方法的复合切点


public ComposablePointcut(ClassFilter classFilter, MethodMatcher methodMatcher)


构造出一个匹配特定类特定方法的复合切点


ComposablePointcut的3个交集运算的方法


20170821055701759.jpg


public ComposablePointcut intersection(ClassFilter other)

将复合切点和一个ClassFilter对象进行交集运算,得到一个结果复合切点


public ComposablePointcut intersection(MethodMatcher other)

将复合切点和一个MethodMatcher对象进行交集运算,得到一个结果复合切点


public ComposablePointcut intersection(Pointcut other)

将复合切点和一个切点对象进行交集运算,得到一个结果复合切点


ComposablePointcut的3个并集运算的方法


20170821055757440.jpg


public ComposablePointcut union(ClassFilter other)

将复合切点和一个ClassFilter对象进行并集运算,得到一个结果复合切点


public ComposablePointcut union(MethodMatcher other)


将复合切点和一个MethodMatcher对象进行并集运算,得到一个结果复合切点


public ComposablePointcut union(Pointcut other)

将复合切点和一个切点对象进行并集运算,得到一个结果复合切点


多个切点之间的交集并集运算


ComposablePointcut没有提供直接对两个切点机型并集交集的运算的方法,如果需要对连个切点进行叫交集并集运算,可以使用Spring提供的 org.springframework.aop.support.Pointcuts工具类,改工具类提供两个非常友好的静态方法


20170821061831230.jpg


public static Pointcut union(Pointcut pc1, Pointcut pc2)

对两个切点进行交集运算,返回一个结果切点,该切点即ComposablePointcut对象的实例


public static Pointcut intersection(Pointcut pc1, Pointcut pc2)

对两个切点进行并集运算,返回一个结果切点,该切点即ComposablePointcut对象的实例


实例


代码已托管到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方法即可得到一个相交的复合切点,配置复合切点的切面和配置其他切点一样,如下所示

<?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.ComposablePointcut.Waiter"/>
    <bean id="greetingComposablePointcut" class="com.xgj.aop.spring.advisor.ComposablePointcut.GreetingComposablePointcut"/>
    <!-- 增强 -->
    <bean id="greetingBeforeAdvice" class="com.xgj.aop.spring.advisor.ComposablePointcut.GreetingBeforeAdvice"/>
    <!-- 切面点   p:pointcut引用getIntersectionPointcut返回的复合切点  
           注意写法 #{greetingComposablePointcut.intersectionPointcut}-->
    <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才织入了增强,这正是复合交集切点所描述的连接点


相关文章
|
8月前
|
XML Java API
Spring AOP切点和通知机制的深度解析
Spring AOP切点和通知机制的深度解析
99 4
|
3月前
|
XML Java 数据库连接
Spring高手之路25——深入解析事务管理的切面本质
本篇文章将带你深入解析Spring事务管理的切面本质,通过AOP手动实现 @Transactional 基本功能,并探讨PlatformTransactionManager的设计和事务拦截器TransactionInterceptor的工作原理,结合时序图详细展示事务管理流程,最后引导分析 @Transactional 的代理机制源码,帮助你全面掌握Spring事务管理。
48 2
Spring高手之路25——深入解析事务管理的切面本质
|
7月前
|
Java Spring
在Spring Boot中使用AOP实现日志切面
在Spring Boot中使用AOP实现日志切面
|
8月前
|
XML Java 数据格式
技术好文:Spring基础篇——AOP切面编程
技术好文:Spring基础篇——AOP切面编程
|
6月前
|
XML Java 数据格式
Spring5入门到实战------11、使用XML方式实现AOP切面编程。具体代码+讲解
这篇文章是Spring5框架的AOP切面编程教程,通过XML配置方式,详细讲解了如何创建被增强类和增强类,如何在Spring配置文件中定义切入点和切面,以及如何将增强逻辑应用到具体方法上。文章通过具体的代码示例和测试结果,展示了使用XML配置实现AOP的过程,并强调了虽然注解开发更为便捷,但掌握XML配置也是非常重要的。
Spring5入门到实战------11、使用XML方式实现AOP切面编程。具体代码+讲解
|
6月前
|
缓存 Java 开发者
Spring高手之路22——AOP切面类的封装与解析
本篇文章深入解析了Spring AOP的工作机制,包括Advisor和TargetSource的构建与作用。通过详尽的源码分析和实际案例,帮助开发者全面理解AOP的核心技术,提升在实际项目中的应用能力。
72 0
Spring高手之路22——AOP切面类的封装与解析
|
6月前
|
Java Spring 容器
SpringBoot整合AOP实现打印方法执行时间切面
SpringBoot整合AOP实现打印方法执行时间切面
59 1
|
6月前
|
XML Java 数据库
Spring5入门到实战------10、操作术语解释--Aspectj注解开发实例。AOP切面编程的实际应用
这篇文章是Spring5框架的实战教程,详细解释了AOP的关键术语,包括连接点、切入点、通知、切面,并展示了如何使用AspectJ注解来开发AOP实例,包括切入点表达式的编写、增强方法的配置、代理对象的创建和优先级设置,以及如何通过注解方式实现完全的AOP配置。
|
7月前
|
Java Spring
在Spring Boot中使用AOP实现日志切面
在Spring Boot中使用AOP实现日志切面
|
8月前
|
缓存 Java API
AOP切面编程
AOP切面编程