java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > java aop切面

Java AOP面向切面编程的概念和实现方式

作者:talenteddriver

AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍Java AOP面向切面编程的概念和实现方式,感兴趣的朋友一起看看吧

一、AOP 是什么?

AOP(Aspect-Oriented Programming),即面向切面编程。它是一种编程范式,与我们所熟悉的OOP(面向对象编程)是互补的关系,而不是替代。

看下面的例子:

面向对象编程OPP完成了穿衣、吃饭、洗碗等这些功能,但从另一个维度去控制这些功能,比如“查看穿衣服、吃饭的时间(性能监控)”、“保证吃饭、洗碗连在一起完成(事务管理)”、“记录洗碗、打扫消耗的用水量(日志记录)”这些就是面向切面编程AOP

二、AOP 的核心概念与实现方式

核心概念

实现方式

Spring AOP 的底层就是基于我们之前讨论过的动态代理

三、Spring AOP 的关键注解

注解说明
@Aspect声明一个类是切面。
@Pointcut声明一个切点表达式,可被通知方法引用,避免重复书写。
@Before前置通知:在目标方法执行之前执行。
@AfterReturning返回通知:在目标方法成功执行并返回后执行。
@AfterThrowing异常通知:在目标方法抛出异常后执行。
@After后置通知:在目标方法执行之后执行(无论成功还是异常,类似于finally)。
@Around环绕通知:最强大的通知类型,可以手动控制目标方法的执行时机,可以在方法执行前后添加自定义行为。

四、实际场景与代码示例

场景一:记录洗碗和打扫的用水量

1. 业务类(核心方法)

WashDish.java - 洗碗类

@Component
public class WashDish {
    private int water;
    public int fillWater(int amount) {
        this.water += amount;
        System.out.println("洗碗接水: " + amount + "升");
        return amount;
    }
    public void wash() {
        System.out.println("使用" + water + "升水洗碗");
        water = 0;
    }
}

CleanRoom.java - 打扫类

@Component
public class CleanRoom {
    private int water;
    public int fillWater(int amount) {
        this.water += amount;
        System.out.println("打扫接水: " + amount + "升");
        return amount;
    }
    public void clean() {
        System.out.println("使用" + water + "升水打扫房间");
        water = 0;
    }
}

2. 切面类(AOP实现)

WaterUsageLoggerAspect.java - 用水量记录切面

/**
* 切面类
*/
@Aspect
@Component
public class WaterUsageLoggerAspect {
    private Map<String, Integer> waterUsageRecords = new HashMap<>();
    /**
     * 切入点:规定哪些类被控制
     */
    @Pointcut("execution(* WashDish.fillWater(..)) || execution(* CleanRoom.fillWater(..))")
    public void waterUsagePointcut() {}
    /**
     * 通知
     */
    @AfterReturning(pointcut = "waterUsagePointcut()", returning = "waterAmount")
    public void logWaterUsage(int waterAmount) {
        String activity = "家务活动";
        waterUsageRecords.put(activity, waterUsageRecords.getOrDefault(activity, 0) + waterAmount);
        System.out.println("记录用水: " + waterAmount + "升,当前总用水量: " + waterUsageRecords.get(activity) + "升");
    }
    public int getTotalWaterUsage() {
        return waterUsageRecords.values().stream().mapToInt(Integer::intValue).sum();
    }
}

3. 配置类(Spring配置)

AppConfig.java - 应用配置

@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.example.aop")
public class AppConfig {
}

4. 测试类(演示代码)

HomeChoresTest.java - 家务测试

public class HomeChoresTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = 
            new AnnotationConfigApplicationContext(AppConfig.class);
        WashDish washDish = context.getBean(WashDish.class);
        CleanRoom cleanRoom = context.getBean(CleanRoom.class);
        WaterUsageLoggerAspect waterLogger = context.getBean(WaterUsageLoggerAspect.class);
        System.out.println("=== 开始家务活动 ===");
        // 洗碗活动
        System.out.println("\n--- 洗碗 ---");
        washDish.fillWater(10);
        washDish.wash();
        // 打扫活动
        System.out.println("\n--- 打扫 ---");
        cleanRoom.fillWater(15);
        cleanRoom.clean();
        System.out.println("\n=== 家务完成 ===");
        System.out.println("总用水量: " + waterLogger.getTotalWaterUsage() + "升");
        context.close();
    }
}

5. 预期输出

运行测试类后,预期输出如下:

=== 开始家务活动 === 
--- 洗碗 --- 
洗碗接水: 10升 
记录用水: 10升,当前总用水量: 10升 
使用10升水洗碗 
--- 打扫 --- 
打扫接水: 15升 
记录用水: 15升,当前总用水量: 25升 
使用15升水打扫房间 
=== 家务完成 === 总用水量: 25升

代码说明

五、AOP 的常见应用场景

总结

通过AOP,我们可以以一种非常优雅和非侵入式的方式,为应用程序添加强大的功能。

到此这篇关于java:AOP面向切面编程的文章就介绍到这了,更多相关java aop切面内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文