Spring AOP:面向切面编程的最佳实践 ( 二 )

3.SpringAOP应用实例

3.1.导入依赖

通过 spring-context 会依赖导入 spring核心包, 而spring-aspects 用于提供AspectJ的支持

xml 复制代码
    <!-- Spring AOP 相关依赖 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>5.3.6</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.6</version>
    </dependency>

    <!-- 如果需要使用代理功能 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>5.3.6</version>
    </dependency>

如果 用于AspectJ的运行时和编译时/加载时编织的功能 还要导入aspectjrt 和 aspectjweaver

xml 复制代码
    <!-- 如果使用 AspectJ 编译时或加载时织入 -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.9.7</version>
    </dependency>
	<dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.7</version>
    </dependency>

3.2.实现代码

3.2.1.业务类

增加 @Component 注册到Spring IoC容器中

java 复制代码
import org.springframework.stereotype.Component;

@Component
public class GymAop {

    // 业务 A : 举重训练
    public String  weightLifting() {
        System.out.println( "进行举重训练。" );
        return "感觉不断在进步!";
    }

    // 业务 B : 瑜伽课
    public void yogaClass(String type) {
        System.out.println( "参加 " + type + " [ 瑜伽课 ]。");
    }

    // 业务 C : 游泳训练
    public void swimming() {
        System.out.println( "在游泳池里游泳。");
    }

}
3.2.2.切面类
java 复制代码
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.swing.*;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;

@Aspect
@Component
public class AspectAop {

    //前置的方法
    // 功能 A : 推荐老师
    @Before("execution(* com.yuan.aop.GymAop.*(..))")
    public void selectMaster(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        String type = "";
        if (args != null && args.length > 0) {
            type = "根据您的要求: " + Arrays.toString( args );
        }
        System.out.println( "首先 : " + type + " 我们为您推荐一位指导老师!" );
    }

    //后置的方法
    //功能 B : 结束提示
    @After("execution(* com.yuan.aop.GymAop.*(..))")
    public void  overTip(JoinPoint joinPoint ){
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        System.out.println( "您在 " + new Date() + " 结束了" + method.getName() );
    }

    //环绕的方法
    @Around("execution(* com.yuan.aop.GymAop.*(..))")
    public Object doBasicProfiling(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object[] args = proceedingJoinPoint.getArgs();
        // 修改 传入的参数
        if (args != null && args.length > 0) {
            for (int i = 0; i < args.length; i++) {
                args[i] = " { " + args[i] + " } ";
            }
        }
        //执行方法
        Object obj = proceedingJoinPoint.proceed(args);

        // 修改 返回值
        if (obj!=null) {
            obj = " { " + obj + " } ";
        }

        // 方法返回值
        return obj;
    }
}
3.2.3.测试类
java 复制代码
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan
@EnableAspectJAutoProxy
public class TestAop {
    public static void main(String[] args)
    {
        AnnotationConfigApplicationContext spring = new AnnotationConfigApplicationContext(TestAop.class);
        GymAop bean = spring.getBean(GymAop.class);

        bean.yogaClass("综合");
        System.out.println("-----");

        String feel = bean.weightLifting();
        System.out.println("您的评价是:" + feel );

        System.out.println("-----");
        bean.swimming();
    }
}
3.2.4.运行测试
text 复制代码
首先 : 根据您的要求: [ { 综合 } ] 我们为您推荐一位指导老师!
参加  { 综合 }  [ 瑜伽课 ]。
您在 Fri Aug 02 21:52:23 CST 2024 结束了yogaClass
-----
首先 :  我们为您推荐一位指导老师!
进行举重训练。
您在 Fri Aug 02 21:52:23 CST 2024 结束了weightLifting
您的评价是: { 感觉不断在进步! } 
-----
首先 :  我们为您推荐一位指导老师!
在游泳池里游泳。
您在 Fri Aug 02 21:52:23 CST 2024 结束了swimming

3.3.xml配置方式

通过 xml 进行配置aop 的方式, 现在通常使用 注解式

xml 复制代码
<?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
           http://www.springframework.org/schema/aop/spring-aop.xsd">
    
	<!-- 定义目标 -->
	<bean id="gymAop" class="com.yuan.aop.GymAop"></bean> 
    
   	<!-- 定义切面 -->
    <bean id="aspectAop" class="com.yuan.aop.AspectAop"></bean> 
     
    <aop:config> 
     <aop:aspect id="myaop" ref="aspectAop"> 
     
         <aop:pointcut id="mycut" expression="execution(* com.yuan.aop.*.*(..))"/> 
     
	     <aop:before  pointcut-ref="mycut" method="selectMaster" /> 
	     <aop:after   pointcut-ref="mycut" method="overTip"/> 
	     <aop:around  pointcut-ref="mycut" method="doBasicProfiling"/> 
     </aop:aspect> 
   </aop:config> 
    
    <!-- 开启AOP自动代理 -->
    <aop:aspectj-autoproxy />
    
</beans>

3.4.SpringBoot中使用AOP

使用SpringBoot,许多相关依赖已经包含在了Spring Boot的starter依赖中

xml 复制代码
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

并且 使用 @SpringBootApplication 代替了 @Configuration, @ComponentScan, @EnableAspectJAutoProxy

相关推荐
bro_Java666几秒前
链表进阶2:双向链表的构建
java·数据结构·链表
DianSan_ERP22 分钟前
多平台订单自动下载与回传的技术实现:从消息推送到状态闭环引言
java·linux·服务器·前端·网络·架构·自动化
Joe_Wang524 分钟前
【从0到1学习JVM · 13】点进JDK源码只有一个分号?搞懂本地方法栈与JNI机制
java·jvm·学习·本地方法栈
AI 算法大模型备案~当当43 分钟前
各地备案数量怎么看:一份属地公告的认读与台账方法
java·数据库·人工智能
智鸟科技GemeOpen开发者智能设备1 小时前
GemeOpen 智能音箱 GSSM0B - 播放控制(Java示例)
java·开发语言·智能音箱
今天的砖头有点烫手啊1 小时前
Java IO/NIO/AIO 演进:从 BIO 到 Netty 的底层逻辑
java·jvm·nio
谢亮_vipxieliang2 小时前
Java 21 新特性实战:Record、Sealed、模式匹配
java·开发语言
霸道流氓气质2 小时前
LLM 应用限流与熔断机制完全指南:从多层防护架构到Java生产级弹性实战
java·开发语言·架构
不会就选b2 小时前
算法日常・每日刷题--<动态规划>1
java·数据结构·算法
晚安code2 小时前
JVM 内存结构入门:程序计数器、虚拟机栈、本地方法栈与堆的溢出诊断
java·jvm