首页 > 编程语言 >AOP面向切面编程

AOP面向切面编程

时间:2024-08-30 19:50:25浏览次数:7  
标签:Spring 编程 MyService 切面 AOP org public

AOP面向切面编程

如何理解面向切面编程

面向切面编程(Aspect-Oriented Programming,简称AOP)是一种编程范式,它允许开发者将横切关注点(如日志记录、事务管理等)与业务逻辑分离,从而提高代码的模块化和可维护性。AOP 通过引入“切面”的概念来实现这一点,切面可以看作是封装了横切关注点的模块。
在这里插入图片描述

举例理解:

面向切面编程(AOP)的一个经典例子是日志记录。在一个应用程序中,你可能有多个服务层方法需要记录每次调用的日志。如果使用传统的面向对象编程(OOP),你需要在每个服务层方法中手动添加日志代码,这会导致代码重复和难以维护。

通过AOP,你可以定义一个日志切面,它将日志记录逻辑封装在一个单独的模块中。这个切面可以配置为在特定方法调用的前后自动执行日志记录,而不需要修改这些方法的代码。下面是一个简化的示例来说明这个过程:

  1. 定义一个日志切面:首先,你创建一个切面类,使用@Aspect注解标记它。
@Aspect
public class LoggingAspect {
    @Before("execution(* com.example.service.*.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        // 获取被调用的方法名和参数
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        // 打印日志
        System.out.println("Before method: " + methodName + ", with args: " + Arrays.toString(args));
    }

    @AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        // 打印返回结果
        System.out.println("After method returned: " + result);
    }
}
  1. 配置Spring AOP:在你的Spring配置中,启用@AspectJ自动代理,以便Spring可以识别上面定义的切面,并自动将日志逻辑织入到应用程序中。
<aop:aspectj-autoproxy/>
  1. 业务逻辑实现:现在,你可以在服务层实现业务逻辑,而不需要关心日志记录的代码。
@Service
public class UserService {
    public User findUserById(Long id) {
        // 业务逻辑
        return userRepository.findById(id);
    }
}

在这个例子中,无论何时调用UserServicefindUserById方法,LoggingAspect中的日志记录逻辑都会自动执行,无需在UserService中添加任何日志代码。这样,日志记录就作为一个横切关注点被模块化了,符合AOP的原则。

核心概念:

  • 切面(Aspect):封装了横切关注点的模块,可以是事务管理、日志记录等。
  • 连接点(Joinpoint):程序执行过程中的特定点,如方法调用或异常处理。
  • 通知(Advice):在切面的连接点上执行的动作,包括前置(Before)、后置(After returning)、异常(After throwing)、最终(After finally)和环绕(Around)通知。
  • 切入点(Pointcut):用来匹配连接点的表达式,决定通知何时执行。
  • 引入(Introduction):允许为类添加新的方法或属性。
  • 目标对象(Target Object):被一个或多个切面所通知的对象。
  • AOP代理(AOP Proxy):AOP框架创建的对象,用于实现切面契约。
  • 织入(Weaving):将切面应用到目标对象上,创建被通知的对象。

Spring AOP

Spring框架中的AOP是一个重要的组成部分,它提供了声明式企业服务和自定义切面的支持。Spring AOP使用纯Java实现,不需要特殊的编译过程,适用于J2EE web容器或应用服务器。

两种配置风格

Spring AOP支持两种配置风格:基于注解的@AspectJ风格和基于XML的schema风格。@AspectJ风格使用Java 5的注解,可以声明切面为普通的Java类,而XML风格则使用aop命名空间来定义切面和通知。

基于注解的@AspectJ风格

首先,需要引入必要的Spring依赖,确保项目中有Spring AOP相关的库。

  1. 依赖配置(Maven)
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>5.3.9</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.9</version>
    </dependency>
</dependencies>
  1. 定义切面类
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {

    // 定义一个切入点,匹配service包下的所有方法
    @Before("execution(* com.example.service.*.*(..))")
    public void logBefore() {
        System.out.println("A method in the service package is being called.");
    }
}
  1. 配置Spring上下文
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = "com.example")
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppConfig {
}
  1. 使用注解配置的Spring AOP
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        MyService service = context.getBean(MyService.class);
        service.doSomething();
    }
}

@Component
public class MyService {
    public void doSomething() {
        System.out.println("Executing service method...");
    }
}

基于XML的Schema风格

  1. Spring AOP配置(XML)
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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:config>
        <aop:aspect ref="loggingAspect">
            <aop:pointcut id="serviceMethods" expression="execution(* com.example.service.*.*(..))"/>
            <aop:before pointcut-ref="serviceMethods" method="logBefore"/>
        </aop:aspect>
    </aop:config>

    <!-- 切面bean -->
    <bean id="loggingAspect" class="com.example.aspect.LoggingAspect"/>

    <!-- 其他bean定义 -->
    <bean id="myService" class="com.example.service.MyService"/>
</beans>
  1. 使用XML配置的Spring AOP
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

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

代理机制

Spring AOP的代理机制可以是基于JDK动态代理或CGLIB代理。如果目标对象实现了至少一个接口,则使用JDK动态代理;如果没有实现任何接口,则使用CGLIB代理。

JDK动态代理

使用JDK动态代理(假设MyService实现了一个接口)

import org.springframework.aop.framework.ProxyFactory;

public class Main {
    public static void main(String[] args) {
        ProxyFactory factory = new ProxyFactory(new MyServiceImpl());
        factory.addAdvice(new LoggingAdvice());
        MyService proxy = (MyService) factory.getProxy();
        proxy.doSomething();
    }
}

CGLIB代理

使用CGLIB代理(MyService不实现任何接口)

import org.springframework.aop.framework.ProxyFactory;

public class Main {
    public static void main(String[] args) {
        ProxyFactory factory = new ProxyFactory(new MyService());
        factory.setProxyTargetClass(true);  // 强制使用CGLIB代理
        factory.addAdvice(new LoggingAdvice());
        MyService proxy = (MyService) factory.getProxy();
        proxy.doSomething();
    }
}

编程方式创建代理

此外,Spring AOP还支持以编程方式创建代理,可以使用AspectJProxyFactory类来为一个或多个@AspectJ切面通知的目标对象创建代理。

  • 使用AspectJProxyFactory
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;

public class Main {
    public static void main(String[] args) {
        MyService target = new MyService();
        AspectJProxyFactory factory = new AspectJProxyFactory(target);
        factory.addAspect(LoggingAspect.class);
        MyService proxy = factory.getProxy();
        proxy.doSomething();
    }
}

配置AspectJ加载时织入

最后,Spring框架还支持使用AspectJ的加载时织入(LTW),这允许在虚拟机载入字节码文件时动态织入AspectJ切面,提供了更细粒度的控制。

META-INF/aop.xml中配置:

<aspectj>
    <weaver>
        <include within="com.example..*"/>
    </weaver>
    <aspects>
        <aspect name="com.example.aspect.LoggingAspect"/>
    </aspects>
</aspectj>

在Spring配置中启用LTW:

<beans>
    <context:load-time-weaver/>
</beans>

还在学习中,内容有误请联系作者,本内容仅供各位大佬了解与讨论。

标签:Spring,编程,MyService,切面,AOP,org,public
From: https://blog.csdn.net/weixin_63405049/article/details/141681571

相关文章

  • Java中的并发控制算法:如何实现高效的锁机制与无锁编程
    Java中的并发控制算法:如何实现高效的锁机制与无锁编程大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在多线程环境中,如何保证数据的正确性和一致性是个重要的问题。为了解决这个问题,Java提供了多种并发控制算法,主要包括锁机制和无锁编程。本文将介......
  • 各个编程语言及其应用领域
    编程语言编译类型开发框架/工具支持的操作系统主要应用领域HTML标记语言N/AWindows,macOS,Linux,Web网页结构定义CSS样式表语言N/AWindows,macOS,Linux,Web网页样式定义SQL查询语言MySQL,PostgreSQL,SQLite,Oracle...Windows,macOS,Linux......
  • pinpoint-php-aop 内部原理
    pinpoint-php-aop是一个支持pinpoint-phpagent的库自动注入PHP内置函数,比如redis,pdo,mysqli自动注入用户类,比如guzzlehttp,predis怎样处理内置函数内置函数解释:PHPcomesstandardwithmanyfunctionsandconstructs.Therearealsofunctionsthatrequir......
  • 最适合程序员的编程字体,好看、优雅!
    对于程序员来说,每天面对最多的就是代码了,选择一款赏心悦目的编程字体就显得尤为重要。那什么是好看的字体呢?基本要求就是相似符号要有明显区别,比如:0、O、o;l、I、1;全角和半角的()等,并且得看着舒服。还有些人认为输入和显示不要有太大的差异,比如:!=展示为≠;===展示为≡等,这个就......
  • Python编程实战营:四款实用小项目助你快速入门,从零开始打造你的个人项目集!
    踏入编程世界的门槛,总是伴随着既兴奋又忐忑的心情。作为Python的新手,你是否渴望通过实际项目来巩固知识、提升技能?本篇文章将引领你踏上一段从理论到实践的精彩旅程,通过四个精心设计的项目,让你在趣味与挑战中快速成长。项目一:简易文本编辑器首先,我们将从基础出发,动手打造一......
  • 物联网虚拟仿真系统通过可视化编程接入迅通云平台
    物联网虚拟仿真系统工作准备进入物联网虚拟仿真系统,拉入传感器并正确接好线后,双击配置仿真设备的随机值。打开物联网虚拟仿真系统本地工具,开启HTTPServer的服务于HTTP端口后,即可看到数据存入客户端在网页上搜索本地IP:8000的网址,即可看到JSON格式的仿真设备数据......
  • 【愚公系列】《AIGC辅助软件开发》002-AI智能化编程助手:GitHub Copilot
    ......
  • 【愚公系列】《AIGC辅助软件开发》002-AI智能化编程助手:GitHub Copilot
    ......
  • 从匿名内部类到Lambda表达式:Java编程的优雅进化
    匿名内部类首先我们先来介绍一下什么是匿名内部类匿名内部类:java中一种特殊的类定义方式,它允许你在需要实现一个接口或继承一个类的地方直接定义一个该接口或类的匿名子类。若想创建一个派生类的对象,并且对象只创建一次,可以设计为匿名内部类,可以大大简化代码注意:匿名内部类......
  • 《C++模板元编程:编程世界的魔法艺术》
    在C++的广阔编程领域中,模板元编程犹如一种神秘而强大的魔法艺术,为开发者打开了一扇通往极致性能与高度灵活性的大门。那么,究竟什么是模板元编程?又该如何在C++中进行模板元编程呢?首先,让我们来理解一下模板元编程的概念。模板元编程是一种在编译期进行计算和代码生成的技术......