Spring Boot原理分析(三):AOP

文章目录

  • 一、AOP设计思想
  • 二、AOP的实现原理
    • 1. 静态代理
    • 2. 动态代理
    • 3. 字节码增强
    • 4. 注解驱动
      • 实现原理
      • 代码示例
    • 5. XML配置
      • 实现原理
      • 代码示例

一、AOP设计思想

AOP(Aspect-Oriented Programming)是一种编程思想,它的目标是将系统的关注点(concern)从核心业务逻辑中分离出来,以便更好地实现模块化、可维护和可扩展的软件系统。AOP的核心思想是通过将横切关注点(cross-cutting concern)从主要业务逻辑中分离出来,以便在不修改原始代码的情况下,将其应用于多个不同的模块和组件。

在传统的面向对象编程中,系统的关注点通常以垂直的方式分布在各个对象中,这导致了代码的重复和难以维护。AOP通过引入横切关注点的概念,将这些关注点从核心业务逻辑中抽离出来,并将其封装为可重用的模块,称为切面(aspect)。切面可以在不同的模块和组件中被应用,从而实现了横向的关注点复用。

AOP的核心机制是通过在运行时动态地将切面织入到目标对象中,从而实现对目标对象的增强。这种织入操作可以在编译时、加载时或运行时进行,具体取决于编程语言和框架的实现方式。一旦切面被织入到目标对象中,它可以在目标对象的方法执行前、执行后或异常抛出时插入额外的逻辑,从而实现横切关注点的功能。

AOP的应用范围广泛,可以用于日志记录、事务管理、安全性控制、性能监控等方面。它提供了一种灵活的方式来管理系统中的关注点,并提高了代码的可维护性和可重用性。通过将关注点从核心业务逻辑中解耦出来,AOP使得系统更易于理解、扩展和维护。

二、AOP的实现原理

AOP的实现方法主要有以下几种:

1. 静态代理

通过手动编写代理类来实现切面逻辑的插入。在编译期间,通过将切面逻辑与目标对象进行织入,生成代理类。代理类在运行时会调用目标对象的方法,并在方法执行前后插入切面逻辑。

关于 静态代理模式及其实现 请看我的这篇博客:链接

2. 动态代理

使用Java的动态代理机制,在运行时动态生成代理类。通过实现InvocationHandler接口,并在invoke()方法中插入切面逻辑,实现对目标对象方法的代理。

关于 动态代理模式及其实现 请看我的这篇博客:链接

3. 字节码增强

通过修改字节码文件来实现切面逻辑的插入。常用的字节码增强框架有ASM、CGLIB和AspectJ等。这些框架可以在编译期间或者运行时修改字节码文件,将切面逻辑织入到目标对象的方法中。

4. 注解驱动

使用注解来标记切面逻辑,并通过解析注解来实现切面逻辑的插入。常用的注解驱动框架有Spring AOP和AspectJ等。这些框架可以通过在目标对象的方法上添加注解,将切面逻辑织入到目标对象的方法中。

实现原理

Spring AOP 的注解驱动实现原理是基于 Java 注解和动态代理 实现的。

在 Spring AOP 中,我们可以使用 @Aspect 注解来定义切面,使用 @Before@After@Around 等注解来定义具体的通知操作。Spring AOP 使用 AspectJ 的注解风格,这使得开发者可以非常方便地使用注解来定义切面和通知操作。

Spring AOP 的注解驱动实现原理可以分为以下几个步骤:

  1. Spring AOP 在应用启动时扫描所有被 @Aspect 注解修饰的类,并为每个切面创建一个代理对象。
  2. 对于每个被 @Aspect 注解修饰的类,Spring AOP 会解析其中的切点表达式,以确定哪些方法需要被代理。
  3. 对于每个需要被代理的方法,Spring AOP 会为其生成一个代理对象,并将代理对象与切面的通知操作绑定起来。
  4. 当代理对象的方法被调用时,Spring AOP 会根据代理对象的类型以及被调用的方法的信息,确定需要执行哪些切面的通知操作。
  5. Spring AOP 使用 JDK 动态代理或 CGLIB 代理等技术,在运行时生成代理对象的字节码,并将其加载到 JVM 中。

总之,Spring AOP 的注解驱动实现原理是基于 Java 注解和动态代理实现的。它使用注解来定义切面和通知操作,使用动态代理来生成代理对象,并在运行时将切面的通知操作织入到代理对象的方法调用中。这种实现方式使得 Spring AOP 的使用非常方便,并且具有很高的灵活性和可扩展性。

代码示例

在这里给出一个简单的 Spring AOP 注解驱动的代码示例,以帮助理解其实现原理。

假设我们有一个 Calculator 接口和其实现类 CalculatorImpl,我们想要在其执行加法和减法方法时,分别打印日志。我们可以通过以下步骤来实现:

  1. CalculatorImpl 类上添加 @Component 注解,使其成为 Spring 容器中的一个 Bean。
  2. 创建一个切面类 LoggingAspect,并使用 @Aspect 注解修饰。
  3. LoggingAspect 中定义一个 @Before 注解修饰的方法 logBefore(),并使用 @Pointcut 注解定义一个切点表达式,用于匹配加法和减法方法。
  4. logBefore() 方法中编写打印日志的逻辑。
  5. 在 Spring 配置文件中开启注解驱动的 AOP,并将 LoggingAspect 注册为一个 Bean。

下面是示例代码:

  • Calculator.java:
public interface Calculator {
    public int add(int a, int b);
    public int sub(int a, int b);
}
  • CalculatorImpl.java:
@Component
public class CalculatorImpl implements Calculator {
    @Override
    public int add(int a, int b) {
        return a + b;
    }
    
    @Override
    public int sub(int a, int b) {
        return a - b;
    }
}
  • LoggingAspect.java:
@Aspect
@Component
public class LoggingAspect {
    @Pointcut("execution(* Calculator.add(..)) || execution(* Calculator.sub(..))")
    public void logPointcut() {}
    
    @Before("logPointcut()")
    public void logBefore() {
        System.out.println("logging before method execution");
    }
}
  • applicationContext.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
         http://www.springframework.org/schema/beans/spring-beans.xsd 
         http://www.springframework.org/schema/aop 
         http://www.springframework.org/schema/aop/spring-aop.xsd">
       
    <aop:aspectj-autoproxy/>
    
    <bean id="calculator" class="com.example.CalculatorImpl"/>
    
    <bean id="loggingAspect" class="com.example.LoggingAspect"/>
    
beans>

在上述示例中,我们使用 @Aspect 注解定义了一个切面类 LoggingAspect,并使用 @Before 注解修饰了一个方法 logBefore(),该方法会在匹配到切点表达式时执行。在 Spring 配置文件中,我们开启了注解驱动的 AOP,并将 LoggingAspect 注册为一个 Bean。

当我们调用 Calculatoradd()sub() 方法时,Spring AOP 会自动将代理对象的方法调用转发到 LoggingAspectlogBefore() 方法中,从而实现了日志记录的功能。

总之,Spring AOP 的注解驱动实现原理是基于 Java 注解和动态代理实现的。它使用注解来定义切面和通知操作,使用动态代理来生成代理对象,并在运行时将切面的通知操作织入到代理对象的方法调用中。

5. XML配置

通过在配置文件中定义切面逻辑和目标对象的关系,实现切面逻辑的插入。常用的XML配置框架有Spring AOP和AspectJ等。这些框架可以通过在配置文件中配置切面和目标对象的关系,将切面逻辑织入到目标对象的方法中。

实现原理

Spring AOP 的 XML 配置实现原理是基于 Spring 配置文件和 AOP 命名空间实现的。

在 Spring AOP 中,我们可以使用 XML 配置文件来定义切面、切点和通知操作等信息。Spring AOP 的 XML 配置实现原理可以分为以下几个步骤:

  1. 在 Spring 配置文件中,使用 aop:aspect 元素定义切面,并使用 aop:pointcut 元素定义切点表达式,用于匹配需要代理的方法。
  2. aop:aspect 元素中,使用 aop:beforeaop:afteraop:around 等元素定义具体的通知操作。
  3. 在 Spring 容器启动时,Spring AOP 会解析配置文件中的切面和通知操作等信息,并将其织入到代理对象的方法调用中。

代码示例

下面是一个简单的 Spring AOP XML 配置示例,以帮助理解其实现原理。

假设我们有一个 Calculator 接口和其实现类 CalculatorImpl,我们想要在其执行加法和减法方法时,分别打印日志。我们可以通过以下步骤来实现:

  1. CalculatorImpl 类上添加 @Component 注解,使其成为 Spring 容器中的一个 Bean。
  2. 在 Spring 配置文件中,使用 aop:aspect 元素定义切面,并使用 aop:pointcut 元素定义切点表达式,用于匹配加法和减法方法。
  3. aop:aspect 元素中,使用 aop:before 元素定义一个前置通知操作,用于打印日志。
  4. 将 Spring AOP 的命名空间声明为 XML 文件的根元素。

下面是示例代码:

Calculator.java:

public interface Calculator {
    public int add(int a, int b);
    public int sub(int a, int b);
}

CalculatorImpl.java:

@Component
public class CalculatorImpl implements Calculator {
    @Override
    public int add(int a, int b) {
        return a + b;
    }
    
    @Override
    public int sub(int a, int b) {
        return a - b;
    }
}

applicationContext.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
         http://www.springframework.org/schema/beans/spring-beans.xsd 
         http://www.springframework.org/schema/aop 
         http://www.springframework.org/schema/aop/spring-aop.xsd">
       
    <aop:aspectj-autoproxy/>
    
    <bean id="calculator" class="com.example.CalculatorImpl"/>
    
    <aop:config>
        <aop:aspect id="loggingAspect" ref="loggingAspectBean">
            <aop:pointcut id="logPointcut" expression="execution(* Calculator.add(..)) || execution(* Calculator.sub(..))"/>
            <aop:before pointcut-ref="logPointcut" method="logBefore"/>
        aop:aspect>
    aop:config>
    
    <bean id="loggingAspectBean" class="com.example.LoggingAspect"/>
    
beans>

LoggingAspect.java:

public class LoggingAspect {
    public void logBefore() {
        System.out.println("logging before method execution");
    }
}

在上述示例中,我们在 Spring 配置文件中使用 aop:aspect 元素定义切面,并使用 aop:pointcut 元素定义切点表达式,用于匹配需要代理的方法。在 aop:aspect 元素中,我们使用 aop:before 元素定义一个前置通知操作,用于打印日志。在 Spring 容器启动时,Spring AOP 会解析配置文件中的切面和通知操作等信息,并将其织入到代理对象的方法调用中。

总之,Spring AOP 的 XML 配置实现原理是基于 Spring 配置文件和 AOP 命名空间实现的。它使用 XML配置文件来定义切面、切点和通知操作等信息,使用 AOP 命名空间来声明和配置切面和通知操作等元素,从而实现代理对象的方法调用拦截和增强。

你可能感兴趣的:(spring,boot,java,后端)