`

Spring基础:AOP编程(2)

阅读更多
基于ProxyFactory的AOP编程

Spring只支持方法连接点,包括了5种类型的增强。
  • 前置增强
  • 后置增强
  • 环绕增强
  • 异常抛出增强
  • 引介增强


1. 前置异常
这里使用一个服务员作为例子,服务员向顾客打招呼,并且提供服务。首先我们创建一个服务员的接口,然后再创建一个不那么友好的服务员,他直接走到顾客面前就开始提供服务了。我们应该给他们做功课,让他们更加有礼貌一些。
public interface Waiter {
    void greetTo(String name);
    void serveTo(String name);
}


就是这个没什么经验的服务员类:
public class NaiveWaiter implements Waiter {
    public void greetTo(String name) {
        System.out.println("greet to " + name + "..");
    }
    public void serveTo(String name) {
        System.out.println("serve to " + name + "..");
    }
}


在这里我们给这个服务加上前置增强类,让这个服务员在见到顾客时先打招呼:
public class GreetingBeforeAdvice implements MethodBeforeAdvice {
    public void before(Method method, Object[] args, Object obj)
            throws Throwable {
        String clientName = (String) args[0];
        System.out.println("How are you! Mr." + clientName + ".");
    }
}


用Spring提供的ProxyFactory进行测试:
public class TestBeforeAdvice {
    public static void main(String[] args) {
        Waiter waiter = new NaiveWaiter();
        BeforeAdvice advice = new GreetingBeforeAdvice();
        ProxyFactory pf = new ProxyFactory();
        // 设置目标类
        pf.setTarget(waiter);
        // 设置增强,这里可以添加多个增强
        pf.addAdvice(advice);
        
        Waiter proxy = (Waiter) pf.getProxy();
        proxy.greetTo("John");
        proxy.serveTo("John");
    }
}


输出:

How are you! Mr.John.
greet to John..
How are you! Mr.John.
serve to John..


当然我们也可以采用Spring的方式来配置增强,需要用ProxyFactoryBean来代替上面的ProxyFactory
<bean id="greetingBefore" class="com.firethewhole.maventest07.advice.GreetingBeforeAdvice"/>
<bean id="target" class="com.firethewhole.maventest07.advice.NaiveWaiter"/>
<bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean"
    p:proxyInterfaces="com.firethewhole.maventest07.advice.Waiter"
    p:interceptorNames="greetingBefore"
    p:proxyTargetClass="true"
    p:target-ref="target"/>

target:代理的目标对象。
proxyInterfaces:代理所要实现的接口,可以有多个。
interfaces:是上面的属性的别名。
interceptorNames:需要织入目标对象的Bean列表。
singleton:返回的代理是否是单例,默认为单例。
optimize:为true时,使用CGLib代理,否则使用JDK代理。
proxyTargetClass:是否对类进行代理(而不是针对接口进行代理),设置为true时,使用CGLib代理。

让我们来测试一下:
String configPath = "com/firethewhole/maventest07/advice/beans.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
Waiter waiter = (Waiter) ctx.getBean("waiter");
waiter.greetTo("John");

输出:

How are you! Mr.John.
greet to John..
How are you! Mr.John.
serve to John..


2. 后置增强:
在为顾客提供完服务之后,也应该有礼貌。
public class GreetingAfterAdvice implements AfterReturningAdvice {
    public void afterReturning(Object returnValue, Method method,
            Object[] args, Object target) throws Throwable {
        System.out.println("Please enjoy yourself!");
    }
}

<bean id="greetingAfter" class="com.firethewhole.maventest07.advice.GreetingAfterAdvice"/>
<bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean"
    p:proxyInterfaces="com.firethewhole.maventest07.advice.Waiter"
    p:interceptorNames="greetingAfter"
    p:proxyTargetClass="true"
    p:target-ref="target"/>


greet to John..
Please enjoy yourself!
serve to John..
Please enjoy yourself!


3. 环绕增强
Spring在这里直接使用了AOP联盟的接口org.aopalliance.intercept.MethodInterceptor
public class GreetingInterceptor implements MethodInterceptor {
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Object[] args = invocation.getArguments();
        String clientName = (String) args[0];
        System.out.println("How are you! Mr." + clientName + ".");
        Object obj = invocation.proceed();
        System.out.println("Please enjoy yourself!");
        return obj;
    }
}

<bean id="greetingAround" class="com.firethewhole.maventest07.advice.GreetingInterceptor"/>
<bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean"
    p:proxyInterfaces="com.firethewhole.maventest07.advice.Waiter"
    p:interceptorNames="greetingAround"
    p:proxyTargetClass="true"
    p:target-ref="target"/>

输出:

How are you! Mr.John.
greet to John..
Please enjoy yourself!
How are you! Mr.John.
serve to John..
Please enjoy yourself!

我们看到方法执行的前后都被织入了增强。

4.异常抛出增强
public class ForumServiceThrowException {
    public void removeForum(int forumId) {
        throw new RuntimeException("运行异常。");
    }
    public void updateForum(int forumId) throws Exception {
        throw new SQLException("数据更新操作异常");
    }
}

public class TransactionManager implements ThrowsAdvice {
    public void afterThrowing(Method method, Object[] args, Object target, Exception ex) throws Throwable{
        System.out.println("---------------");
        System.out.println("method:" + method.getName());
        System.out.println("抛出异常:" + ex.getMessage());
        System.out.println("成功回滚事务。");
    }
}


这里进行配置织入异常抛出增强
<bean id="transacionManager" class="com.firethewhole.maventest07.advice.TransactionManager"/>
<bean id="forumServiceTarget" class="com.firethewhole.maventest07.advice.ForumServiceThrowException"/>
<bean id="forumService" class="org.springframework.aop.framework.ProxyFactoryBean"
    p:interceptorNames="transacionManager"
    p:proxyTargetClass="true"
    p:target-ref="forumServiceTarget"/>

****我在采用上面的测试程序进行测试的时候,发现确实在抛出异常之后,走到了增强之中,但是在增强代码结束之后,最终异常还是会被抛出。

4. 引介增强
引介增强和上面的增强都不太一样,可以理解为在运行时为一个类对象添加了新的功能,这将极大地改变我们编写代码时的思路。

这里添加一个新的接口,为性能监视类添加是否需要监控的功能。
public interface Monitorable {
    void setMonitorActivate(boolean active);
}


这里是增强类
public class ControllablePerformanceMonitor extends
        DelegatingIntroductionInterceptor implements Monitorable {
    
    private ThreadLocal<Boolean> monitorStatusMap = new ThreadLocal<Boolean>();

    public void setMonitorActivate(boolean active) {
        monitorStatusMap.set(active);
    }
    
    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        Object obj = null;
        if (monitorStatusMap.get() != null && monitorStatusMap.get()) {
            PerformanceMonitor.begin(mi.getClass().getName() + "."
                    + mi.getMethod().getName());
            obj = super.invoke(mi);
            PerformanceMonitor.end();
        } else {
            obj = super.invoke(mi);
        }
        return obj;
    }
}


配置文件:
<bean id="pmonitor" class="com.firethewhole.maventest07.introduce.ControllablePerformanceMonitor"/>
<bean id="forumServiceTarget" class="com.firethewhole.maventest07.introduce.ForumService"/>
<bean id="forumService" class="org.springframework.aop.framework.ProxyFactoryBean"
    p:interfaces="com.firethewhole.maventest07.introduce.Monitorable"
    p:target-ref="forumServiceTarget"
    p:interceptorNames="pmonitor"
    p:proxyTargetClass="true"/>


测试程序:
String configLocation = "com/firethewhole/maventest07/introduce/beans.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(configLocation);
ForumService forumService = (ForumService) ctx.getBean("forumService");
forumService.removeForum(10);
forumService.removeTopic(1022);

Monitorable moniterable = (Monitorable) forumService;
moniterable.setMonitorActivate(true);
forumService.removeForum(20);
forumService.removeTopic(1022);


输出:

模拟删除Forum记录:10
模拟删除Topic记录:1022
begin monitor...
模拟删除Forum记录:20
end monitor...
org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.removeForum花费20毫秒。
begin monitor...
模拟删除Topic记录:1022
end monitor...
org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.removeTopic花费20毫秒。


可以看到在更改可检测属性为true之后,增强才变的有效的。
分享到:
评论

相关推荐

    Spring基础:AOP编程(4)

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

    Spring基础:AOP编程(1)

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

    Spring基础:AOP编程(5)

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

    Spring基础:AOP编程(3)

    **Spring AOP编程详解** 在Java开发中,Spring框架因其强大的功能和易用性而备受推崇,其中AOP(Aspect-Oriented Programming,面向切面编程)是其核心特性之一。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这个东西就不是觉得有什么神秘了! 阅读对象:凡是喜爱...

    Spring4—AOP编程

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

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

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

Global site tag (gtag.js) - Google Analytics