Spring AOP原理以及简化版代码还原AOP实现

1. Spring AOP简介

Spring AOP(面向切面编程)是Spring框架的一个核心特性,它允许开发人员通过在应用程序中定义切面和切点来实现横切关注点的模块化。AOP可以帮助解耦业务逻辑和横切关注点(如日志记录、事务管理、安全性等),提高代码的可维护性和可重用性。

1.1. 核心概念

面向切面编程(AOP)时,有几个关键概念需要了解。以下是 AOP 的核心概念:

  1. 切面(Aspect):切面是一个模块化的单元,它封装了与横切关注点相关的行为。它定义了在哪个连接点执行什么样的操作。切面可以包括前置通知、后置通知、环绕通知、异常通知和最终通知。

  2. 连接点(Join Point):连接点是应用程序执行过程中可以插入切面的点。它是在应用程序中定义的具体点,如方法调用、方法执行、异常抛出等。

  3. 切点(Pointcut):切点是连接点的集合,用于定义在哪些连接点上应用切面。切点可以使用表达式或模式来指定连接点。

  4. 通知(Advice):通知是在切点上执行的具体操作,它定义了在何时执行切面的代码。常见的通知类型包括Before:前置通知(在连接点之前执行)、After:后置通知(在连接点之后执行)、Around:环绕通知(在连接点前后执行)、After-throwing:异常通知(在连接点抛出异常时执行)和After-returning:最终通知(无论连接点如何结束,总是执行)。

  5. 引入(Introduction):引入允许向现有类添加新的接口和方法。它使得可以在不修改源代码的情况下,向现有类添加新的行为。

  6. 目标对象(Target Object):目标对象是被一个或多个切面所通知的对象。它是应用程序中的真正业务对象。

  7. 织入(Weaving):织入是将切面应用到目标对象以创建新的代理对象的过程。织入可以发生在编译时、加载时或运行时。

  8. 代理(Proxy):代理是包装目标对象的对象,它可以控制对目标对象的访问,并在访问时应用切面的行为。代理可以是静态代理或动态代理。

以上概念共同构成了 AOP 的基本框架。AOP 通过将横切关注点从业务逻辑中分离出来,提供了一种模块化的方式来处理横切关注点,从而提高了代码的可维护性和可重用性。

2.AOP的使用

@Aspect
@Component
@Slf4j
public class LogInterceptor {
    /**
     * 执行拦截
     */
    @Around("execution(* com.stukk.stuoj.controller.*.*(..))")
    public Object doInterceptor(ProceedingJoinPoint point) throws Throwable {
        //添加你想添加的业务,比如拦截登录鉴权、打印日志等等
        log.info("输出");
        // 执行原方法
        Object result = point.proceed();
        // 输出日志
        log.info("输出");
        return result;
    }
}

3. 实现原理

Spring AOP的实现原理是基于动态代理。当一个类被声明为切面时,Spring会在运行时创建一个代理对象,该代理对象包含了原始对象的所有方法,并在切点处织入切面的横切逻辑。当应用程序调用代理对象的方法时,代理对象会在适当的时机执行切面逻辑。

下面是一个简单的示例,演示了如何使用动态代理实现一个简化版的 Spring AOP。

首先,定义一个接口 UserService

public interface UserService {
    void sayHello();
}

然后,创建一个实现类 UserServiceImpl

public class UserServiceImpl implements UserService {
    @Override
    public void sayHello() {
        System.out.println("Hello from UserServiceImpl!");
    }
}

接下来,创建一个切面类 LoggingAspect,它包含了需要织入的横切逻辑(即在方法调用前后打印日志):

public class LoggingAspect implements InvocationHandler {
    private Object target;

    public LoggingAspect(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before method: " + method.getName());
        Object result = method.invoke(target, args);
        System.out.println("After method: " + method.getName());
        return result;
    }
}

最后,我们可以使用动态代理来创建代理对象,并将切面逻辑织入到原始对象的方法调用中:

import java.lang.reflect.Proxy;

public class Main {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();

        // 创建代理对象
        UserService proxy = (UserService) Proxy.newProxyInstance(
                userService.getClass().getClassLoader(),
                userService.getClass().getInterfaces(),
                new LoggingAspect(userService)
        );

        // 调用代理对象的方法
        proxy.sayHello();
    }
}

运行上述代码,你将看到以下输出:

Before method: sayHello
Hello from UserServiceImpl!
After method: sayHello

这个简化的示例演示了使用动态代理实现的简化版 Spring AOP。通过创建代理对象并在方法调用前后执行切面逻辑,我们成功将日志记录的横切关注点与原始对象的业务逻辑解耦,实现了横切关注点的模块化。

猜你喜欢

转载自blog.csdn.net/m0_54409739/article/details/134981562
今日推荐