首页 > 编程语言 >什么是AOP面向切面编程?怎么简单理解?

什么是AOP面向切面编程?怎么简单理解?

时间:2024-11-05 19:09:52浏览次数:2  
标签:调用 编程 织入 切面 Aspect AOP 方法

本文原文地址:什么是AOP面向切面编程?怎么简单理解?

什么是AOP面向切面编程

面向切面编程(AOP)通过将横切关注点(cross-cutting concerns)分离出来,提供了一种增强代码模块化和可维护性的方法。

简单来说,AOP就是将公共的模块封装成公共的方法,然后在需要的时候(这个就是切入点),直接就可以调用,而不用在各个对象里面具体的实现。

AOP是一种新的编程方式,它和OOP不同,OOP把系统看作多个对象的交互,AOP把系统分解为不同的关注点,或者称之为切面(Aspect)。这个可以理解为把系统理解为一个流程,一个对象负责流程上的一个节点。

当然,AOP和公共模块抽取调用的方式的差别在于切入点的调用方式的不同。AOP是通过某种方式(下面AOP原理会解释)自动的调用,而不管是抽取公共方法,还是通过Proxy模式实现调用,都需要在每个业务方法上重复编写调用。

以AOP的视角来编写上述业务,可以依次实现:

  • 核心逻辑,即BookService;
  • 切面逻辑,即:
    1. 权限检查的Aspect;
    2. 日志的Aspect;
    3. 事务的Aspect。

然后,以某种方式,让框架来把上述3个Aspect以Proxy的方式“织入”到BookService中,这样一来,就不必编写复杂而冗长的Proxy模式或者公共方法调用。

AOP原理

如何把切面织入到核心逻辑中?这正是AOP需要解决的问题。换句话说,如果客户端获得了BookService的引用,当调用bookService.createBook()时,如何对调用方法进行拦截,并在拦截前后进行安全检查、日志、事务等处理,就相当于完成了所有业务功能。

在Java平台上,对于AOP的织入,有3种方式:

  1. 编译期:在编译时,由编译器把切面调用编译进字节码,这种方式需要定义新的关键字并扩展编译器,AspectJ就扩展了Java编译器,使用关键字aspect来实现织入;
  2. 类加载器:在目标类被装载到JVM时,通过一个特殊的类加载器,对目标类的字节码重新“增强”;
  3. 运行期:目标对象和切面都是普通Java类,通过JVM的动态代理功能或者第三方库实现运行期动态织入。

最简单的方式是第三种,Spring的AOP实现就是基于JVM的动态代理。由于JVM的动态代理要求必须实现接口,如果一个普通类没有业务接口,就需要通过CGLIB或者Javassist这些第三方库实现。

AOP技术看上去比较神秘,但实际上,它本质就是一个动态代理,让我们把一些常用功能如权限检查、日志、事务等,从每个业务方法中剥离出来。

需要特别指出的是,AOP对于解决特定问题,例如事务管理非常有用,这是因为分散在各处的事务代码几乎是完全相同的,并且它们需要的参数(JDBC的Connection)也是固定的。另一些特定问题,如日志,就不那么容易实现,因为日志虽然简单,但打印日志的时候,经常需要捕获局部变量,如果使用AOP实现日志,我们只能输出固定格式的日志,因此,使用AOP时,必须适合特定的场景。

核心概念

  • 切面(Aspect):切面是封装横切关注点的模块。它定义了在何处以及如何应用这些关注点。
  • 连接点(Join Point):连接点是程序执行过程中可以插入切面的点。例如,方法调用、方法执行、构造函数调用、字段访问等。
  • 切入点(Pointcut):切入点定义了在哪些连接点上应用切面。它通常使用表达式来匹配特定的连接点。
  • 通知(Advice):通知是在特定的切入点上执行的代码。通知可以在方法执行之前、之后或异常抛出时执行。常见的通知类型包括:
    • 前置通知(Before):在方法执行之前执行。
    • 后置通知(After):在方法执行之后执行。
    • 返回通知(After Returning):在方法成功返回之后执行。
    • 异常通知(After Throwing):在方法抛出异常之后执行。
    • 环绕通知(Around):包围方法的执行,可以在方法执行之前和之后自定义行为。
  • 织入(Weaving):织入是将切面应用到目标对象的过程。织入可以在编译时、类加载时或运行时进行。

示例

以下是一个使用 Spring AOP 的简单示例,展示了如何定义和应用切面。

  1. 定义切面
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class LoggingAspect {

    @Before("execution(* com.example.service.*.*(..))")
    public void logBeforeMethod() {
        System.out.println("Method is about to be executed");
    }
}

在这个示例中,LoggingAspect 是一个切面,它包含一个前置通知 logBeforeMethod。这个通知将在 com.example.service 包中的所有方法执行之前运行。

  1. 配置 Spring AOP
    在 Spring 配置文件中启用 AOP 支持,并注册切面:
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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="loggingAspect" class="com.example.aspect.LoggingAspect"/>
</beans>
  1. 使用目标对象
package com.example.service;

public class UserService {
    public void createUser() {
        System.out.println("Creating user");
    }
}
  1. 测试 AOP
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.example.service.UserService;

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService) context.getBean("userService");
        userService.createUser();
    }
}

运行这个示例时,输出将会是:

Method is about to be executed
Creating user

这表明前置通知在 createUser 方法执行之前被调用了。

AOP 通过将横切关注点分离出来,提供了一种增强代码模块化和可维护性的方法。通过定义切面、连接点、切入点和通知,可以在不修改现有代码的情况下,动态地将横切关注点织入到程序中。

标签:调用,编程,织入,切面,Aspect,AOP,方法
From: https://www.cnblogs.com/the-pig-of-zf/p/18528598

相关文章

  • 实验3 类和对象_基础编程2
    实验任务1bottom.hpp#pragmaonce#include<iostream>#include<string>usingstd::string;usingstd::cout;//按钮类classButton{public:Button(conststring&text);stringget_label()const;voidclick();private:string......
  • 计算思维的核心是编程思维
    计算思维的核心是编程思维编程作为一门基础技能,正逐渐从专业领域的“小众”走向大众视野的“主流”。正如乔布斯所言:“学编程,教你另一种思考方式。”编程不仅仅是一种技能,更是一种能够深刻影响我们思维模式的强大工具。提到编程,很多人首先想到的是程序员、代码和计算机。然而,编......
  • 第9天:网络编程
    第9天,我们将深入了解如何在Android应用中进行网络编程,涉及HTTP请求、JSON数据解析以及如何处理网络权限的具体步骤。内容概述本节学习内容代码链接为NetworkExample1.HTTP请求Android提供了多种方法来执行HTTP请求,我们将重点关注以下几种:HttpURLConnection:AndroidS......
  • springboot+vue沧交编程论坛的设计与实现 前8【开题+程序+论文】
    系统程序文件列表开题报告内容研究背景随着互联网技术的迅猛发展,编程技术已成为现代社会不可或缺的一部分。作为技术交流与学习的平台,编程论坛扮演着至关重要的角色。然而,现有的编程论坛往往存在功能单一、用户体验不佳等问题,无法满足广大编程爱好者与从业者日益增长的需求......
  • Python编程风格:EAFP防御
    在Python编程的世界里,有一种非常重要的编程风格,称为“EAFP”(EasiertoAskforForgivenessthanPermission,意为“请求宽恕比请求许可更容易”)。这一风格与许多其他编程语言中的常见做法形成了鲜明对比。在这篇博文中,我们将深入探讨EAFP的概念,包括其历史背景、基本原则、在实......
  • 实验3 类和对象_基础编程2
    1.实验任务1button.hpp1#pragmaonce2#include<iostream>3#include<string>4usingstd::string;5usingstd::cout;6//按钮类7classButton{8public:9Button(conststring&text);10stringget_label()const;11......
  • 实验3 类和对象_基础编程2
    任务1button.hpp1#pragmaonce23#include<iostream>4#include<string>56usingstd::string;7usingstd::cout;89//按钮类10classButton{11public:12Button(conststring&text);13stringget_label()const;1......
  • 【洛谷 P3695 CYaRon!语】从一道大模拟入坑自制编程语言
    原题传送门本来是想投题解的,但是仔细阅读了一下主题库题解规范,发现这篇文章更加适合单独作为一篇blog阅读而非挂在题解区里污染环境,所以就这样了。0xff开始之前这道题我很早以前就开始看了,那时还只有星野梦美大佬的一篇题解。而到现在,我终于是有了时间和能力来切掉这道题,......
  • 程序员推荐的笔记本,2024年六款高性能笔记本电脑推荐!非常适合计算机专业,做编程设计的程
    文|二加一网络科技对于计算机相关专业,尤其是学习编程或程序员来说,选择一款高性能的笔记本电脑至关重要,它不仅能够提供流畅稳定的编程环境,还能助力高效地完成各项工作。接下来,小编就来推荐六款2024年非常适合编程的高性能笔记本电脑,看看哪一款能够成为你的得力助手。第......
  • 实验四 C语言数组应用编程
    实验四C语言数组应用编程实验任务1——内存地址#include<stdio.h>#defineN4#defineM2voidtest1(){ intx[N]={1,9,8,4}; inti; //输出数组x占用的内存字节数 printf("sizeof(x)=%d\n",sizeof(x)); //输出每个元素的地址、值 for(i=0;i<N;+......