代码优雅的转变:基于注解的AOP编程在Spring中的实践

简介: 代码优雅的转变:基于注解的AOP编程在Spring中的实践


定义切面类

package world.xuewei.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
/**
 * 自定义切面类
 *
 * @author 薛伟
 * @since 2023/10/23 9:45
 */
@Aspect
public class MyAspect {
    /**
     * 定义切入点方法,方法体内编写额外功能
     * 注解 @Around:用于定义切入点,编写切入点表达式
     */
    @Around(value = "execution(* *(..))")
    public Object around(ProceedingJoinPoint joinPoint) {
        // 在此处编写前置操作
        System.out.println("Before");
        Object result = null;
        try {
            result = joinPoint.proceed();
        } catch (Throwable e) {
            // 在此处编写异常操作
            System.out.println("Exception");
        }
        // 在此处编写后置操作
        System.out.println("After");
        // 可以在此处编写新的返回值并返回
        return result;
    }
}

Spring 配置文件

<?xml version="1.0" encoding="UTF-8"?>
<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 https://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 开启 AOP 注解驱动开发 -->
    <aop:aspectj-autoproxy/>
    <!-- 注册原始对象 -->
    <bean id="userService" class="world.xuewei.proxy.UserServiceImpl"/>
    <!-- 注册自定义切面类 -->
    <bean id="around" class="world.xuewei.aspect.MyAspect"/>
</beans>

切入点复用

package world.xuewei.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
/**
 * 自定义切面类
 *
 * @author 薛伟
 * @since 2023/10/23 9:45
 */
@Aspect
public class MyAspect {
    /**
     * 单独定义切入点,只需要关注注解
     */
    @Pointcut("execution(* *(..))")
    public void p1() {
    }
    /**
     * 定义切入点方法,方法体内编写额外功能
     * 注解 @Around:用于定义切入点,编写切入点表达式
     */
    @Around(value = "p1()")
    public Object around(ProceedingJoinPoint joinPoint) {
        // 在此处编写前置操作
        System.out.println("Before");
        Object result = null;
        try {
            result = joinPoint.proceed();
        } catch (Throwable e) {
            // 在此处编写异常操作
            System.out.println("Exception");
        }
        // 在此处编写后置操作
        System.out.println("After");
        // 可以在此处编写新的返回值并返回
        return result;
    }
    @Around(value = "p1()")
    public Object around1(ProceedingJoinPoint joinPoint) {
        // 在此处编写前置操作
        System.out.println("Before");
        Object result = null;
        try {
            result = joinPoint.proceed();
        } catch (Throwable e) {
            // 在此处编写异常操作
            System.out.println("Exception");
        }
        // 在此处编写后置操作
        System.out.println("After");
        // 可以在此处编写新的返回值并返回
        return result;
    }
}

强制使用 Cglib 动态代理

<aop:aspectj-autoproxy proxy-target-class="true"/>

坑:代理方法调用

在同一个业务类中,进行业务方法间的调用时,只有最外层的方法才是通过代理对象调用的(加入了额外功能),内部调用的本类的其他方法都是通过原始对象调用,如果想要让内部的方法也通过代理对象调用,那么就需要实现 ApplicationContextAware 接口。

package world.xuewei.proxy;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
 * 用户服务实现
 *
 * @author 薛伟
 * @since 2023/10/18 17:49
 */
public class UserServiceImpl implements UserService, ApplicationContextAware {
    private ApplicationContext context;
    @Override
    public void register() {
        System.out.println("UserServiceImpl.register");
        UserService p = context.getBean(、"userService", UserService.class);
        p.login();
    }
    @Override
    public void login() {
        System.out.println("UserServiceImpl.login");
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
    }
}



相关文章
|
8月前
|
存储 人工智能 Java
AI 超级智能体全栈项目阶段四:学术分析 AI 项目 RAG 落地指南:基于 Spring AI 的本地与阿里云知识库实践
本文介绍RAG(检索增强生成)技术,结合Spring AI与本地及云知识库实现学术分析AI应用,利用阿里云Qwen-Plus模型提升回答准确性与可信度。
2335 90
AI 超级智能体全栈项目阶段四:学术分析 AI 项目 RAG 落地指南:基于 Spring AI 的本地与阿里云知识库实践
|
9月前
|
XML 安全 Java
使用 Spring 的 @Aspect 和 @Pointcut 注解简化面向方面的编程 (AOP)
面向方面编程(AOP)通过分离横切关注点,如日志、安全和事务,提升代码模块化与可维护性。Spring 提供了对 AOP 的强大支持,核心注解 `@Aspect` 和 `@Pointcut` 使得定义切面与切入点变得简洁直观。`@Aspect` 标记切面类,集中处理通用逻辑;`@Pointcut` 则通过表达式定义通知的应用位置,提高代码可读性与复用性。二者结合,使开发者能清晰划分业务逻辑与辅助功能,简化维护并提升系统灵活性。Spring AOP 借助代理机制实现运行时织入,与 Spring 容器无缝集成,支持依赖注入与声明式配置,是构建清晰、高内聚应用的理想选择。
827 0
|
10月前
|
Java API 开发者
Spring 控制反转与依赖注入:从玄学编程到科学管理
在传统开发中,手动`new`对象导致紧耦合、难以维护和测试。控制反转(IoC)将对象创建交给框架,实现解耦。Spring通过IOC容器自动管理对象生命周期,开发者只需声明依赖,无需关心创建细节。依赖注入(DI)是IoC的具体实现方式,支持构造器、Setter和字段注入。构造器注入推荐使用,保证依赖不可变且易于测试。对于多个同类型Bean,可用`@Qualifier`或`@Primary`解决冲突。此外,Spring还支持依赖查找(DL),开发者主动从容器获取Bean,适用于动态场景,但侵入性强。掌握IoC与DI,有助于构建灵活、可维护的Spring应用。
|
8月前
|
监控 Java Spring
AOP 切面编程
AOP(面向切面编程)通过动态代理在不修改源码的前提下,对方法进行增强。核心概念包括连接点、通知、切入点、切面和目标对象。常用于日志记录、权限校验、性能监控等场景,结合Spring AOP与@Aspect、@Pointcut等注解,实现灵活的横切逻辑管理。
1954 6
AOP 切面编程
|
8月前
|
XML Java 数据格式
《深入理解Spring》:AOP面向切面编程深度解析
Spring AOP通过代理模式实现面向切面编程,将日志、事务等横切关注点与业务逻辑分离。支持注解、XML和编程式配置,提供五种通知类型及丰富切点表达式,助力构建高内聚、低耦合的可维护系统。
|
8月前
|
人工智能 监控 Java
Spring AI Alibaba实践|后台定时Agent
基于Spring AI Alibaba框架,可构建自主运行的AI Agent,突破传统Chat模式限制,支持定时任务、事件响应与人工协同,实现数据采集、分析到决策的自动化闭环,提升企业智能化效率。
Spring AI Alibaba实践|后台定时Agent
|
10月前
|
监控 Java Spring
AOP切面编程快速入门
AOP(面向切面编程)通过分离共性逻辑,简化代码、减少冗余。它通过切点匹配目标方法,在不修改原方法的前提下实现功能增强,如日志记录、性能监控等。核心概念包括:连接点、通知、切入点、切面和目标对象。Spring AOP支持多种通知类型,如前置、后置、环绕、返回后、异常通知,灵活控制方法执行流程。通过@Pointcut可复用切点表达式,提升维护性。此外,结合自定义注解,可实现更清晰的切面控制。
761 5
|
10月前
|
Java 应用服务中间件 开发者
Spring Boot 技术详解与应用实践
本文档旨在全面介绍 Spring Boot 这一广泛应用于现代企业级应用开发的框架。内容将涵盖 Spring Boot 的核心概念、核心特性、项目自动生成与结构解析、基础功能实现(如 RESTful API、数据访问)、配置管理以及最终的构建与部署。通过本文档,读者将能够理解 Spring Boot 如何简化 Spring 应用的初始搭建和开发过程,并掌握其基本使用方法。
724 2
Micronaut AOP与代理机制:实现应用功能增强,无需侵入式编程的秘诀
AOP(面向切面编程)能够帮助我们在不修改现有代码的前提下,为应用程序添加新的功能或行为。Micronaut框架中的AOP模块通过动态代理机制实现了这一目标。AOP将横切关注点(如日志记录、事务管理等)从业务逻辑中分离出来,提高模块化程度。在Micronaut中,带有特定注解的类会在启动时生成代理对象,在运行时拦截方法调用并执行额外逻辑。例如,可以通过创建切面类并在目标类上添加注解来记录方法调用信息,从而在不侵入原有代码的情况下增强应用功能,提高代码的可维护性和可扩展性。
374 1