You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot结合AspectJ:能否拦截java.util.ArrayList.size()方法调用?

关于Spring Boot AOP拦截第三方库方法的疑问与解决

兄弟,我来给你把这个问题掰明白:第三方库的方法完全可以被拦截,但你用Spring AOP默认的动态代理机制根本做不到,这就是你写的切面没生效的核心原因。

为啥你的切面没起作用?

Spring AOP默认依赖JDK动态代理或者CGLIB代理,但这俩有个致命前提:被代理的对象必须是Spring容器管理的Bean。你想想,java.util.ArrayList这种JDK自带的类,你平时都是直接new ArrayList<>()创建实例吧?这种对象根本不在Spring的管控范围内,Spring AOP的切面自然碰不到它。

那该咋整?用AspectJ——这是真正的字节码增强框架,能直接修改类的字节码,不管对象是不是Spring Bean,只要加载到JVM里就能拦截。

下面给你一步步说具体实现:

1. 先把依赖加全

在你的Maven pom.xml里添上这俩依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
</dependency>

2. 开启AspectJ的织入机制

AspectJ有两种织入方式,选一个适合你的:

方式一:编译时织入(CTW)

这种方式会在编译阶段就把切面逻辑织入到目标类的字节码里,需要给Maven加个编译插件:

<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <version>1.14.0</version>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                        <goal>test-compile</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <complianceLevel>17</complianceLevel> <!-- 改成你用的JDK版本 -->
                <source>17</source>
                <target>17</target>
                <aspectLibraries>
                    <aspectLibrary>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-aspects</artifactId>
                    </aspectLibrary>
                </aspectLibraries>
            </configuration>
        </plugin>
    </plugins>
</build>

方式二:加载时织入(LTW)

这种更灵活,不用改编译配置,只要在运行时把切面织入到类中:

  • 先在application.properties里开启配置:
spring.aop.proxy-target-class=true
spring.aspectj.weaver.auto=true
  • 然后在项目的src/main/resources/META-INF下新建aop.xml文件,配置要织入的目标类和切面:
<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "https://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
    <weaver>
        <!-- 指定要拦截的包,这里包含java.util -->
        <include within="java.util..*"/>
        <!-- 你的切面所在的包 -->
        <include within="com.yourproject..*"/>
    </weaver>
    <aspects>
        <!-- 把你的切面类全路径写上 -->
        <aspect name="com.yourproject.aspect.ListSizeInterceptor"/>
    </aspects>
</aspectj>

3. 修正你的切面代码

你的原切面有俩坑:

  1. 返回值处理错了:@Around方法如果目标方法有返回值,必须返回proceed()的结果,不然调用方拿不到size()的返回值
  2. 切面类没加Spring的注解,要让Spring扫描到它才能生效

修正后的代码如下:

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class ListSizeInterceptor {
    @Around("execution(int java.util.ArrayList.size())")
    public Object interceptListSize(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("[Before] About to call ArrayList.size()");
        // 执行原方法并保存返回值
        Object result = joinPoint.proceed();
        System.out.println("[After] Called ArrayList.size(), result: " + result);
        // 一定要返回结果,不然调用方会拿到null
        return result;
    }
}

最后提几个注意点

  • 拦截JDK核心类的方法要慎重!比如ArrayList.size()被调用得非常频繁,切面逻辑一定要尽量简单,别影响性能
  • 如果用LTW,某些场景下可能需要给JVM加启动参数:-javaagent:path/to/aspectjweaver.jar,不过Spring Boot大部分场景已经帮你处理好了
  • 如果你只是想拦截Spring Bean里用到的ArrayList,也可以把ArrayList包装成Spring Bean(比如用@Bean方法创建),然后用Spring AOP拦截,但这种方式只能拦截Bean实例的调用,管不了所有ArrayList对象

内容的提问来源于stack exchange,提问作者prometheusnoob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:42:30