Skip to content

注册 LoadTimeWeaver

LoadTimeWeaver 被 Spring 用于在类加载到 Java 虚拟机(JVM)时对其进行动态转换。

启用加载时织入

要启用加载时织入(Load-Time Weaving),你可以在你的一个 @Configuration 类上添加 @EnableLoadTimeWeaving 注解,如下例所示:

java
@Configuration
@EnableLoadTimeWeaving
public class AppConfig {
}
kotlin
@Configuration
@EnableLoadTimeWeaving
class AppConfig

或者,对于 XML 配置,可以使用 context:load-time-weaver 元素:

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

一旦为 ApplicationContext 配置了 LoadTimeWeaver,该 ApplicationContext 中的任何 Bean 都可以实现 LoadTimeWeaverAware 接口,从而接收到加载时织入器实例的引用。这在结合 Spring 的 JPA 支持时特别有用,因为 JPA 的类转换可能需要加载时织入。有关更多详细信息,请参阅 LocalContainerEntityManagerFactoryBean 的 JavaDoc。有关 AspectJ 加载时织入的更多信息,请参阅 在 Spring Framework 中使用 AspectJ 进行加载时织入


补充教学

1. 什么是加载时织入 (LTW)?

加载时织入(Load-Time Weaving, LTW)是指在 JVM 加载类文件时,通过字节码转换技术(Instrumentation)动态地修改类的字节码。

在 AOP(面向切面编程)的语境下,它与另外两种常见的织入方式形成对比:

  • 编译时织入 (Compile-Time Weaving):在使用 AspectJ 编译器(ajc)编译源代码时直接修改生成的字节码。
  • 运行时织入 (Runtime Weaving/Proxying):Spring 默认使用的机制,通过 JDK 动态代理或 CGLIB 在运行时创建代理对象。

2. 为什么需要 LTW?

虽然 Spring 的运行时代理能解决 90% 的需求,但 LTW 在以下场景中至关重要:

  • AspectJ 全功能支持:Spring AOP 只支持方法级别的拦截,且只能拦截通过 Spring 容器管理的 Bean。LTW 可以拦截 new 出来的对象、静态方法、构造函数等。
  • 性能优化:在某些场景下,直接修改字节码比运行时创建代理对象的调用开销更小。
  • JPA 实体转换:在使用 Hibernate 或 EclipseLink 等 JPA 实现时,为了实现高性能的延迟加载(Lazy Loading)和脏检查(Dirty Checking),通常需要对实体类(Entity)进行字节码增强。

3. 环境依赖:Java Agent

启用 LoadTimeWeaver 通常需要一个 Java Agent。当你运行应用程序时,需要添加如下 JVM 参数:

bash
-javaagent:path/to/spring-instrument.jar

Spring 会尝试根据当前的容器环境(如 Tomcat, GlassFish, JBoss 等)自动检测合适的 LoadTimeWeaver。如果检测失败且没有提供 Java Agent,织入功能将无法正常工作。

4. @EnableLoadTimeWeaving 的高级配置

@EnableLoadTimeWeaving 注解提供了一个 aspectjWeaving 属性:

  • AspectJWeaving.ENABLED: 启用 AspectJ 织入。
  • AspectJWeaving.DISABLED: 禁用 AspectJ 织入(默认)。
  • AspectJWeaving.AUTODETECT: 如果类路径下存在 META-INF/aop.xml 文件,则启用。
java
@Configuration
@EnableLoadTimeWeaving(aspectjWeaving = AspectJWeaving.ENABLED)
public class AppConfig { }

5. LoadTimeWeaverAware 接口

如果你的自定义组件需要手动操作字节码转换,可以实现此接口:

java
@Component
public class MyBytecodeModifier implements LoadTimeWeaverAware {
    private LoadTimeWeaver loadTimeWeaver;

    @Override
    public void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver) {
        this.loadTimeWeaver = loadTimeWeaver;
    }

    public void addTransformer() {
        loadTimeWeaver.addTransformer(new MyClassTransformer());
    }
}

Based on Spring Framework.