JavaEE企业级应用开发教程——第八章 Spring AOP(黑马程序员第二版)(SSM)

第八章 Spring AOP

8.1 Spring AOP介绍

Spring AOP(面向切面编程)是Spring框架的一个重要模块,它通过在应用程序中定义切面(Aspect)和切点(Pointcut)来实现横向关注点(cross-cutting concerns)的处理。这样,应用程序的业务逻辑就可以专注于核心功能,而不需要处理与横向关注点相关的问题,例如事务管理、安全性、缓存、日志记录等。

8.1.1 Spring AOP概述

AOPOOP的区别在于它们解决问题的角度不同。OOP从面向对象的角度出发,将程序中的功能划分为对象,通过封装、继承、多态等手段来实现代码的重用和扩展。而AOP则从横向关注点的角度出发,将程序中的功能划分为**切面,**通过将切面织入到目标对象的方法中,实现对目标方法的增强

在传统的业务处理代码中,通常都会进行一些通用的操作,如事务处理、日志记录等。虽然使用OOP可以通过组合或继承来实现代码的重用,但是如果要实现某个功能(如日志记录),同样的代码仍然会分散到各个方法中。如果想要关闭某个功能或者对其进行修改,就必须修改所有相关的方法,增加了开发人员的工作量和代码的出错率。

AOP可以为此类问题提供完美的解决方案。它将通用功能抽取到独立的模块中,通过将这些切面织入到目标方法中,实现对目标方法的增强,从而降低横向业务逻辑之间的耦合,减少重复代码。例如,在订单系统中,添加订单、更新订单和删除订单的方法中都包含事务管理业务代码,这会带来一定数量的重复代码和维护成本。使用AOP可以将事务管理业务逻辑从这些方法中抽取到一个可重用的模块中,提高程序的可重用性和开发效率。

AOP的使用使开发人员在编写业务逻辑时可以专注于核心业务,而不必过多地关注其他业务逻辑的实现,这提高了开发效率并且增强了代码的可维护性。因此,AOP和OOP都是提高程序可重用性和可维护性的重要手段,它们可以互相补充,共同使用。

想增强一个方法,又不想修改这个方法里的内容,因为我增强的部分可能是和业务逻辑无关的(比如打印日志),在不修改原方法的内容的情况下给其增加功能,这就是切面编程的作用。


8.1.2 Spring AOP术语

AOP并不是一个新的概念,在Java 语言中早就出现了类似的机制。

AOP的实现机制与Java平台的EJB规范、Servlet规范和Struts2框架中的拦截器机制非常相似,都是把通用的功能抽象成切面,然后在目标对象的方法执行前后添加增强处理,以实现对目标对象的增强。下面是AOP中的一些常用术语的简单介绍:

  1. 切面(Aspect):切面是一个模块化的横切关注点(cross-cutting concern),它包含一组通知和切入点,在目标对象的方法执行前后或者抛出异常时执行特定的操作。

  2. 连接点(Join point):连接点是指那些被拦截到的点,在Java中,这些点指的是方法的调用或者异常的处理等。

  3. 切入点(Pointcut):切入点是指那些我们要对哪些连接点进行拦截的定义,通常使用表达式来定义切入点。

  4. 通知/增强处理(Advice):通知是指在切面的某个特定连接点上执行的动作,它包括了Before、After、Around、AfterReturning和AfterThrowing等类型。

  5. 目标对象(Target):目标对象是指那些被切面通知的对象,也就是我们要对哪些对象进行增强的定义。

  6. 织入(Weaving):织入是指把切面应用到目标对象并创建新的代理对象的过程。

  7. 代理(Proxy):代理是指对目标对象进行包装,以便实现在目标对象执行前后添加增强处理的功能。

  8. 引介(Introduction):引介是一种特殊的通知类型,它允许向现有的类添加新的方法或属性,类似于Java中的接口实现。


这8个术语的应用例子:

假设我们有一个简单的图形计算器程序,其中有一个计算矩形面积的方法,我们想在该方法执行前后记录日志,并且在矩形对象的属性发生变化时自动更新矩形对象的面积,可以使用AOP来实现这个功能。下面是一个简单的实现示例:

1. 定义切面类
@Component
@Aspect
public class LoggingAndCalculatingAspect {
   
    @Before("execution(* com.example.calculator.RectangleCalculator.calculateArea(..))")
    public void logBefore(JoinPoint joinPoint) {
   
        System.out.println("Before calculating area...");
    }

    @AfterReturning("execution(* com.example.calculator.RectangleCalculator.calculateArea(..))")
    public void logAfterReturning(JoinPoint joinPoint) {
   
        System.out.println("Area calculated successfully.");
    }

    @Around("execution(* com.example.calculator.Rectangle.get*(..))")
    public Object calculateAndUpdateArea(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
   
        Object result = proceedingJoinPoint.proceed();
        if (proceedingJoinPoint.getTarget() instanceof Rectangle) {
   
            Rectangle rectangle = (Rectangle) proceedingJoinPoint.getTarget();
            rectangle.setArea(rectangle.getLength() * rectangle.getWidth());
        }
        return result;
    }

    @DeclareParents(value = "com.example.calculator.Rectangle+", defaultImpl = com.example.calculator.RectangleImpl.class)
    public static RectangleMixin rectangleMixin;
}

interface RectangleMixin {
   
    double getArea();
    void setArea(double area);
}

class RectangleImpl implements RectangleMixin {
   
    private double area;

    public double getArea() {
   
        return area;
    }

    public void setArea(double area) {
   
        this.area = area;
    }
}
2. 定义业务逻辑类
@Service
public class RectangleCalculator {
   
    public double calculateArea(Rectangle rectangle) {
   
        return rectangle.getLength() * rectangle.getWidth();
    }
}

class Rectangle {
   
    private double length;
    private double width;

    public Rectangle(double length, double width) {
   
        this.length = length;
        this.width = width;
    }

    public double getLength() {
   
        return length;
    }

    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值