`

Spring基础:AOP编程(3)

阅读更多
基于切面的AOP编程

通过Advice,可以创建方法前,后,环绕之类的增强,但是这是类级别的增强,如果想要深入到方法级别,就需要配合使用切点Pointcut。Advice和Pointcut组合就形成了一个切面。切面增强就是基于方法层面的。

1.切点(Pointcut)
    用于过滤类,getClassFilter()返回ClassFilter类,在这个类里面有一个方法用于判断该对象是否满足匹配条件,boolean matches(Class<?> clazz)。
    用于过滤方法,getMethodMatcher()返回MethodMatcher,在该类里面有boolean matches(Method method, Class<?> targetClass)用于静态匹配方法,boolean matches(Method method, Class<?> targetClass, Object[] args)用于动态匹配。

2 切点的分类
  • StaticMethodMatcherPointcut 静态方法切点
  • DynamicMethodMatcherPointcut 动态方法切点
  • AnnotationMatchingPointcut 注解切点
  • AspectJExpressionPointcut 支持AspectJ语法的表达式切点
  • ControlFlowPointcut 流程切点
  • ComposablePointcut 复合切点


静态方法切点又分两种
  • NameMatchMethodPointcut 用于方法名匹配
  • JdkRegexpMethodPointcut 用于正则匹配


3 切面
  切面分三种
  • Advisor 一般切面,仅包含一个增强方法,不包含切点信息
  • PointcutAdvisor 包含切点的切面,用起来比较灵活
  • IntroductionAdvisor 引介切面


而PointcutAdvisor又分为以下6种
  • DefaultPointcutAdvisor 最常用的切面,可以通过任意组合切点和增强构建切面
  • NameMatchMethodPointcutAdvisor 通过方法名来定义切面
  • RegexpMethodPointcutAdvisor 通过正则表达式匹配方法名来定义切面
  • StaticMethodMatcherPointcutAdvisor 默认情况下,匹配所有目标类
  • AspectJExpressionPointcutAdvisor 用AspectJ切点表达式来匹配
  • AspectJPointcutAdvisor 用AspectJ语法来匹配


4 例子
准备基础类和一个增强类
public class Waiter {
    public void greetTo(String name) {
        System.out.println("waiter greet to " + name + "...");
    }
    
    public void serveTo(String name) {
        System.out.println("waier serving to " + name + "...");
    }
}
public class Seller {
    public void greetTo(String name) {
        System.out.println("seller greet to " + name + "...");
    }
}个
// 前置增强
public class GreetingBeforeAdvice implements MethodBeforeAdvice {

    public void before(Method method, Object[] args, Object obj)
            throws Throwable {
        System.out.println(obj.getClass().getName() + "." + method.getName());
        String clientName = (String) args[0];
        System.out.println("How are you! Mr." + clientName);
    }
}

4.1 静态方法匹配:
public class GreetingAdvisor extends StaticMethodMatcherPointcutAdvisor {
    public boolean matches(Method method, Class<?> targetClass) {
        return "greetTo".equals(method.getName());
    }
    public ClassFilter getClassFilter() {
        return new ClassFilter() {
            public boolean matches(Class<?> clazz) {
                return Waiter.class.isAssignableFrom(clazz);
            }
        };
    }
}

因为GreetingAdvisor类中已经包含切点信息,所以只要配置增强类即可。
<bean id="waiterTarget" class="com.firethewhole.maventest07.advisor.Waiter"/>
<bean id="sellerTarget" class="com.firethewhole.maventest07.advisor.Seller"/>
<bean id="greetingAdvice" class="com.firethewhole.maventest07.advisor.GreetingBeforeAdvice"/>
<bean id="greetingAdvisor" class="com.firethewhole.maventest07.advisor.GreetingAdvisor"
    p:advice-ref="greetingAdvice"/>
<bean id="parent" abstract="true" class="org.springframework.aop.framework.ProxyFactoryBean"
    p:interceptorNames="greetingAdvisor"
    p:proxyTargetClass="true"/>
<bean id="waiter" parent="parent" p:target-ref="waiterTarget"/>
<bean id="seller" parent="parent" p:target-ref="sellerTarget"/>


测试:
String configPath = "com/firethewhole/maventest07/advisor/beans.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
Waiter waiter = (Waiter) ctx.getBean("waiter");
Seller seller = (Seller) ctx.getBean("seller");
waiter.greetTo("John");
waiter.serveTo("John");
seller.greetTo("John");


输出:
只有Waiter类的greetTo方法被织入增强

com.firethewhole.maventest07.advisor.Waiter.greetTo
How are you! Mr.John
waiter greet to John...
waier serving to John...
seller greet to John...


4.2 正则匹配方法名增强
<bean id="regexpAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"
    p:advice-ref="greetingAdvice">
    <property name="patterns">
        <list><value>.*greet.*</value></list>
    </property>
</bean>
<bean id="waiter1" class="org.springframework.aop.framework.ProxyFactoryBean"
    p:interceptorNames="regexpAdvisor"
    p:target-ref="waiterTarget"
    p:proxyTargetClass="true"/>

Waiter waiter1 = (Waiter) ctx.getBean("waiter1");
waiter1.greetTo("John");
waiter1.serveTo("John");


输出:
只有greetTo方法被织入增强

com.firethewhole.maventest07.advisor.Waiter.greetTo
How are you! Mr.John
waiter greet to John...
waier serving to John...


4.3 动态方法匹配
动态方法匹配之前都会先进性静态方法匹配,如果失败才会进行
public class GreetingDynamicPointcut extends DynamicMethodMatcherPointcut {
    private static List<String> specialClientList = new ArrayList<String>();
    static {
        specialClientList.add("John");
        specialClientList.add("Tom");
    }
    public ClassFilter getClassFilter() {
        return new ClassFilter() {
            public boolean matches(Class<?> clazz) {
                System.out.println("调用getClassFilter()对" + clazz.getName() + "做静态检查。");
                return Waiter.class.isAssignableFrom(clazz);
            }
        };
    }
    public boolean matches(Method method, Class<?> clazz) {
        System.out.println("调用matches(method,clazz)对" + clazz.getName() + "." + method.getName() + "做静态检查。");
        return "greetTo".equals(method.getName());
    }
    public boolean matches(Method method, Class<?> clazz, Object[] args) {
        System.out.println("调用matches(method,clazz)对" + clazz.getName() + "." + method.getName() + "做动态检查。");
        String clientName = (String) args[0];
        return specialClientList.contains(clientName);
    }
}

<bean id="greetingDynamicPointcut" class="com.firethewhole.maventest07.advisor.GreetingDynamicPointcut"/>
<bean id="dynamicAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"
    p:pointcut-ref="greetingDynamicPointcut"
    p:advice-ref="greetingAdvice"/> 
<bean id="waiter2" class="org.springframework.aop.framework.ProxyFactoryBean"
    p:interceptorNames="dynamicAdvisor"
    p:target-ref="waiterTarget"
    p:proxyTargetClass="true"/>

Waiter waiter2 = (Waiter) ctx.getBean("waiter2");
waiter2.greetTo("Peter");
waiter2.serveTo("Peter");
waiter2.greetTo("John");
waiter2.serveTo("John");

输出:

调用getClassFilter()对com.firethewhole.maventest07.advisor.Waiter做静态检查。
调用matches(method,clazz)对com.firethewhole.maventest07.advisor.Waiter.greetTo做静态检查。
调用getClassFilter()对com.firethewhole.maventest07.advisor.Waiter做静态检查。
调用matches(method,clazz)对com.firethewhole.maventest07.advisor.Waiter.serveTo做静态检查。
调用getClassFilter()对com.firethewhole.maventest07.advisor.Waiter做静态检查。
调用matches(method,clazz)对com.firethewhole.maventest07.advisor.Waiter.toString做静态检查。
调用getClassFilter()对com.firethewhole.maventest07.advisor.Waiter做静态检查。
调用matches(method,clazz)对com.firethewhole.maventest07.advisor.Waiter.clone做静态检查。
调用getClassFilter()对com.firethewhole.maventest07.advisor.Waiter做静态检查。
调用matches(method,clazz)对com.firethewhole.maventest07.advisor.Waiter.greetTo做静态检查。
调用matches(method,clazz)对com.firethewhole.maventest07.advisor.Waiter.greetTo做动态检查。
waiter greet to Peter...
调用getClassFilter()对com.firethewhole.maventest07.advisor.Waiter做静态检查。
调用matches(method,clazz)对com.firethewhole.maventest07.advisor.Waiter.serveTo做静态检查。
waier serving to Peter...
调用matches(method,clazz)对com.firethewhole.maventest07.advisor.Waiter.greetTo做动态检查。
com.firethewhole.maventest07.advisor.Waiter.greetTo
How are you! Mr.John
waiter greet to John...
waier serving to John...


4.4 流程切面
对配置在某一个类中的某一个方法中直接或间接使用的类进行增强
public class WaiterDelegate {
    private Waiter waiter;
    public void setWaiter(Waiter waiter) {
        this.waiter = waiter;
    }
    public void service(String name) {
        waiter.greetTo(name);
        waiter.serveTo(name);
    }
}

<bean id="controlFlowPointcut" class="org.springframework.aop.support.ControlFlowPointcut">
    <constructor-arg type="java.lang.Class" value="com.firethewhole.maventest07.advisor.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="greetingAdvice"/>
<bean id="waiter3" class="org.springframework.aop.framework.ProxyFactoryBean"
    p:interceptorNames="controlFlowAdvisor"
    p:target-ref="waiterTarget"
    p:proxyTargetClass="true"/>

Waiter waiter3 = (Waiter) ctx.getBean("waiter3");
WaiterDelegate wd = new WaiterDelegate();
wd.setWaiter(waiter3);
waiter3.serveTo("Peter");
waiter3.greetTo("Peter");
wd.service("Peter");


输出:
只有流程切点中的才会被织入增强

waier serving to Peter...
waiter greet to Peter...
com.firethewhole.maventest07.advisor.Waiter.greetTo
How are you! Mr.Peter
waiter greet to Peter...
com.firethewhole.maventest07.advisor.Waiter.serveTo
How are you! Mr.Peter
waier serving to Peter...


4.5 复合增强
public class GreetingComposablePointcut {
    public Pointcut getIntersectionPointcut() {
        ComposablePointcut cp = new ComposablePointcut();
        Pointcut pt1 = new ControlFlowPointcut(WaiterDelegate.class, "service");
        Pointcut pt2 = new NameMatchMethodPointcut();
        ((NameMatchMethodPointcut)pt2).addMethodName("greetTo");
        return cp.intersection(pt1).intersection(pt2);
    }
}

<bean id="gcp" class="com.firethewhole.maventest07.advisor.GreetingComposablePointcut"/>
<bean id="compsableAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"
    p:pointcut="#{gcp.getIntersectionPointcut()}"
    p:advice-ref="greetingAdvice"/>
<bean id="waiter4" class="org.springframework.aop.framework.ProxyFactoryBean"
    p:interceptorNames="compsableAdvisor"
    p:target-ref="waiterTarget"
    p:proxyTargetClass="true"/>

Waiter waiter4 = (Waiter) ctx.getBean("waiter4");
WaiterDelegate wd2 = new WaiterDelegate();
wd2.setWaiter(waiter4);
waiter4.serveTo("Peter");
waiter4.greetTo("Peter");
wd2.service("Peter");


输出:
只有流程切点中的方法名为greetTo才会被织入增强

waier serving to Peter...
waiter greet to Peter...
com.firethewhole.maventest07.advisor.Waiter.greetTo
How are you! Mr.Peter
waiter greet to Peter...
waier serving to Peter...


4.6 引介增强
引介增强是类级别的织入,主要的类有DefaultIntroductionAdvisor,配置方法如下:
<bean id="introduceAdvisor" class="org.springframework.aop.support.DefaultIntroductionAdvisor">
    <constructor-arg>
        <bean class="com.firethewhole.maventest07.introduce.ControllablePerformanceMonitor/>
    </constructor-arg>
</bean>
分享到:
评论

相关推荐

    Spring基础:AOP编程(4)

    在本篇博客“Spring基础:AOP编程(4)”中,我们将深入探讨Spring框架中的面向切面编程(Aspect-Oriented Programming,简称AOP),这是一个强大的功能,它允许我们在不修改原有业务代码的情况下,实现对系统中横切...

    Spring基础:AOP编程(1)

    这篇博客“Spring基础:AOP编程(1)”可能介绍了AOP的基础知识及其在Spring中的实现。 面向切面编程(AOP)是一种编程范式,旨在减少代码的重复性,提高模块间的解耦度。AOP通过将横切关注点(如日志、事务管理、...

    Spring基础:AOP编程(2)

    在本篇关于“Spring基础:AOP编程(2)”的文章中,我们将深入探讨Spring框架中的面向切面编程(Aspect-Oriented Programming, AOP),这是一种强大的设计模式,它允许我们分离关注点,尤其是那些横切关注点,如日志、...

    Spring基础:AOP编程(5)

    在本篇博文中,我们将深入探讨Spring框架中的一个核心特性——面向切...通过以上介绍,我们对Spring中的AOP编程有了基本了解。在实际开发中,AOP可以帮助我们更好地组织代码,降低复杂度,提高代码的可维护性和可读性。

    Spring AOP面向方面编程原理:AOP概念

    Spring AOP是在Spring框架的基础上实现的一种面向方面编程机制。 1. **方面(Aspect)**:这是AOP的核心概念之一,指代一个关注点的模块化,该关注点可能会横切多个对象。例如事务管理就是一个典型的横切关注点,...

    Spring基础:Spring AOP简单使用

    Spring AOP,全称Aspect Oriented Programming(面向切面编程),是Spring框架的重要组成部分,它扩展了传统的面向对象编程(OOP),使得开发者能够更好地处理系统中的横切关注点,如日志、事务管理、权限控制等。...

    小马哥讲 Spring AOP 编程思想 - API 线索图.pdf

    在讨论Spring AOP(面向切面编程)时,首先需要理解几个核心概念。Spring AOP 是Spring框架提供的一个功能模块,它允许开发者将横切关注点(cross-cutting concerns)从业务逻辑中解耦出来,通过在方法调用前后进行...

    hualinux spring 3.15:Spring AOP.pdf

    根据提供的文件内容,可以提取出以下知识点: ...文档中提到的实践示例,例如前置通知、后置通知、返回通知、异常通知和环绕通知的具体编码实现,都是通过具体的代码示例来说明如何在Spring中应用AspectJ进行AOP编程。

    spring-boot aop

    Spring Boot AOP(面向切面编程)是一种强大的设计模式,它允许我们在不修改现有代码的情况下,插入额外的功能或监控代码。在Spring框架中,AOP主要用于日志记录、事务管理、性能统计等场景。本示例是关于如何在...

    spring AOP切面编程

    Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架的重要组成部分,它扩展了传统的面向对象编程,使得开发者可以方便地实现横切关注点,如日志、事务管理、性能监控等。在Spring中,AOP通过代理...

    spring源代码分析:aop的实现

    其中,面向切面编程(Aspect Oriented Programming,简称AOP)是Spring的重要特性之一,它极大地简化了代码中的横切关注点,如日志、事务管理等。本文将深入Spring源码,探索AOP的实现原理。 首先,我们需要理解AOP...

    AOP_使用spring框架进行面向切面编程

    面向切面编程(AOP)是一种编程范式,它旨在减少代码中的重复部分,特别是那些与核心业务逻辑无关但又必须处理...同时,通过分析和操作`springAOP`压缩包中的示例代码,可以更直观地了解AOP在Spring框架中的具体实现。

    Spring中aop编程所需要的jar包

    为了在Spring中进行AOP编程,我们需要一些特定的JAR包。以下是对这些关键组件的详细说明: 1. **Spring核心包**: - `spring-core.jar`: 这是Spring框架的基础,包含了IoC(Inversion of Control,控制反转)容器...

    Spring切面AOP编程的简单模拟实现

    在Spring框架中,AOP(面向切面编程)是一种强大的设计模式,它允许开发者将关注点从核心业务逻辑中分离出来,例如日志记录、事务管理等。本教程将通过模拟Spring AOP来阐述如何实现一个简单的切面编程。我们将讨论...

    spring-aop-jar

    在IT领域,Spring框架是一个广泛使用的Java应用框架,它提供了许多功能,包括依赖注入、面向切面编程(AOP)等。"spring-aop-jar"这个主题涉及到Spring框架中的核心组件之一——Spring AOP。这里我们将深入探讨...

    使用动态代理演示Spring的AOP编程原理

    为了说明Spring的AOP原理,本人使用代理模式中的动态代理完成演示AOP编程的原理的演示。相信,如果你耐心看完整个程序(几乎一行注释一行代码),那么你对Spring这个东西就不是觉得有什么神秘了! 阅读对象:凡是喜爱...

    spring aop 编程所需要的搜友JAR包

    Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架的重要组成部分,它提供了一种在不修改源代码的情况下,对程序进行功能增强的技术。AOP的核心概念是切面(Aspect)、通知(Advice)、连接点...

    Spring4—AOP编程

    Spring AOP,全称Aspect-Oriented Programming(面向切面编程),是Spring框架的一个重要特性,主要用于解决程序中的横切关注点,如日志、事务管理、安全性等。AOP通过将这些关注点与核心业务逻辑分离,实现了代码的...

Global site tag (gtag.js) - Google Analytics