注册 LoadTimeWeaver
LoadTimeWeaver 被 Spring 用于在类加载到 Java 虚拟机(JVM)时对其进行动态转换。
启用加载时织入
要启用加载时织入(Load-Time Weaving),你可以在你的一个 @Configuration 类上添加 @EnableLoadTimeWeaving 注解,如下例所示:
@Configuration
@EnableLoadTimeWeaving
public class AppConfig {
}@Configuration
@EnableLoadTimeWeaving
class AppConfig或者,对于 XML 配置,可以使用 context:load-time-weaver 元素:
<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 参数:
-javaagent:path/to/spring-instrument.jarSpring 会尝试根据当前的容器环境(如 Tomcat, GlassFish, JBoss 等)自动检测合适的 LoadTimeWeaver。如果检测失败且没有提供 Java Agent,织入功能将无法正常工作。
4. @EnableLoadTimeWeaving 的高级配置
@EnableLoadTimeWeaving 注解提供了一个 aspectjWeaving 属性:
AspectJWeaving.ENABLED: 启用 AspectJ 织入。AspectJWeaving.DISABLED: 禁用 AspectJ 织入(默认)。AspectJWeaving.AUTODETECT: 如果类路径下存在META-INF/aop.xml文件,则启用。
@Configuration
@EnableLoadTimeWeaving(aspectjWeaving = AspectJWeaving.ENABLED)
public class AppConfig { }5. LoadTimeWeaverAware 接口
如果你的自定义组件需要手动操作字节码转换,可以实现此接口:
@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());
}
}