说说在 Spring AOP 中如何实现类加载期织入(LTW)
我们可以在类加载期通过字节码编辑技术将切面织入目标类,这种方式叫做 LTW(Load Time Weaving)。
AspectJ LTW 使用 Java 5.0 提供的代理功能实现织入工作 。JDK 的代理功能能够让代理器访问到 JVM 的底层部件,借此向 JVM 注册类文件转换器,在类加载时对类文件的字节码进行转换 。 AspectJ LTW 是基于 JDK 动态代理技术实现的,所以它的作用范围是整个 JVM ,因此这种方式较为粗放,对于单一 JVM 多个应用的场景并不适用 。
相对于 AspectJ LTW, Spring LTW 提供了细粒度的控制,支持在单个 ClassLoader 范围内实施类文件转换,且配置更为简单。
1 instrument 包的工作原理
JDK5.0 新增了 java.lang.instrument 包,它包含能对 JVM 底层组件进行访问的类 。 我们可以在启动时通过 JVM 的 java agent 代理参数获取 JVM 内部组件的引用,以便在后续操作中使用 。 借助 JDK 动态代理,我们可以在 JVM 启动时装配并应用 ClassTransformer,对类字节码进行转换,从而实现 AOP 功能。
java.lang.instrument 包含两个重要接口。
1.1 ClassFileTransformer
它是 Class文件转换器接口,它定义了一个方法:
byte[]transform( ClassLoader loader,String className,Class<?> classBeingRedefined,ProtectionDomain protectionDomain,byte[] classfileBuffer)throws IllegalClassFormatException;
该方法实现对 Class 文件的字节码进行转换, classfileBuffer 是类文件对应的字节码数组,返回的 byte[] 为转换后的字节码 。 如果返回 null ,则表示不进行字节码转换。
1.2 Instrumentation
代表 JVM 内部的一个构件 可以通过该接口的方法向 JVM 的 Instrumentation 注册一些 ClassFileTransformer ,注册转换器的接口方法为:
voidaddTransformer(ClassFileTransformer transformer, boolean canRetransform);
当 ClassFileTransformer 实例注册到 JVM 后, JVM 在加载 Class 文件时,会先调用这个 ClassFileTransformer 的 transform() 方法对 Class 文件的字节码进行转换 。 如果向 JVM 中注册多个 ClassFileTransformer ,它们将按注册的顺序被调用 。 这样 ClassFileTransformer 的实现者就可以从 JVM 层面截获所有类的字节码,并加入希望添加的逻辑 。
下图描绘了拥有多个转换器的 JVM 从加载类到最终生成对应的类字节码的过程:
2 使用 LTW 织入切面
Spring LTW 支持 AspectJ 定义的切面,既可以是直接采用 AspectJ 语法定义的切面,也可以是采用基于 @AspectJ 注解通过 Java 类定义的切面。Spring LTW 采用了与 AspectJ LTW 相同的基础架构,即利用类路径下的 META-INF/aop.xml
配置文件找到切面定义及切面所要实施的候选目标类,通过 LoadTimeWeaver 在 ClassLoader 加载类文件时将切面织入目标类中。
利用特定 Web 容器的 ClassLoader ,通过 LoadTimeWeaver 将 Spring 提供的 ClassFileTransformer 注册到容器的 ClassLoader 中 。在类加载期间,注册的 ClassFileTransformer 会读取 AspectJ 的配置文件,即类路径下的 META-INF/aop.xml 文件,获取切面,接着对 Bean 类进行字节码转换,织入切面 。Spring 容器初始化 Bean 实例时,采用的 Bean 类就是已经被织入切面的类。
2.1 LoadTimeWeaver
大多数的 Web 应用服务器 ( 除了 Tomcat ) 的 ClassLoader 无需通过 javaagent 参数指定代理,即可支持直接访问 Instrument。拥有这种能力的 ClassLoader 被称之为 “ 组件使能( instrumentation-capable ) ”。 通过组件使能能力,我们就可以方便地访问 ClassLoader 的 Instrument。 Spring 使用 Web 应用服务器类加载器,为这些应用服务器分别提供了专门的 LoadTimeWeaver, 以便向特定的 ClassLoader 注册 ClassFileTransformer ,然后再对指定的类进行字节码转换,实现切面的织入 。
Spring 的 org.springframework.instrument.classloading.LoadTimeWeaver
接口定义了类加载期织入器的高层协议,该接口包含三个方法。
方法 | 说明 |
---|---|
void addTransformer(ClassFileTransformer transformer)
|
新增 transformer 到织入器。 |
ClassLoader getInstrumentableClassLoader()
|
返回具有 Instrument 功能的 ClassLoader。 |
ClassLoader getThrowawayClassLoader()
|
返回可丢弃的 ClassLoader。 |
2.2 配置 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:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- 启用装载期织入--><context:load-time-weaver/>
</beans>
2.3 配置 Tomcat
这里以 Tomcat6.x 和 Tomcat7.x 为例。
- 首先在该页面中下载对应 Spring 框架版本的 spring-instrument-tomcat-{version}.jar,然后复制到
<TOMCAT_HOME>/lib
下,该 JAR 只有两个类,其中一个即是 TomcatInstrumentableClassLoader 类。 - 接着在 META-INF 目录下,新建 context.xml,内容为:
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/xxx" docBase="xxx"><loader
loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"useSystemClassLoaderAsParent="false"/>
</Context>
通过以上配置,Tomcat 容器就支持直接在类加载期实现织入功能啦O(∩_∩)O~
2.4 具有组件使能的 Web 应用服务器
具有组件使能的 Web 应用服务器有以下这几种:
- BEA WebLogic 10.0+
- OC4J 10.1.3.1+
- Resin 3.1+
- JBoss 5.x+
如果应用是运行在这些Web 应用服务器中,那么我们就只需在 Spring 中配置 <context:load-time-weaver/>
就可以啦O(∩_∩)O~
说说在 Spring AOP 中如何实现类加载期织入(LTW)相关推荐
- Spring AOP中定义切点PointCut详解
1.AOP是什么? 软件工程有一个基本原则叫做"关注点分离"(Concern Separation),通俗的理解就是不同的问题交给不同的部分去解决,每部分专注于解决自己的问题.这年 ...
- 第十篇 Spring AOP中Load Time Weaver
文章目录 前言 一.先聊Load Time 二.再说Weaver 三.回看Load Time Weaver 四.LTW初始化过程 1.激活 2. Weave过程 总结 前言 本文介绍Spring AO ...
- Spring AOP中定义切点(PointCut)和通知(Advice)
本文讨论一下Spring AOP编程中的两个关键问题,定义切点和定义通知,理解这两个问题能应付大部分AOP场景. 如果你还不熟悉AOP,请先看AOP基本原理,本文的例子也沿用了AOP基本原理中的例子. ...
- 正确理解Spring AOP中的Around advice
Spring AOP中,有Before advice和After advice,这两个advice从字面上就可以很容易理解,但是Around advice就有点麻烦了. 乍一看好像是Before ad ...
- Spring : Spring AOP 中的增强(Advice)或者通知
1.美图 2.概述 概念参考:Spring :Spring AOP 中的一些术语 很多人将增强理解为通知,但是理解为增强会更加准确,因为它表示在连接点上执行的行为,这个行为是目标类类所没有的,是为目标 ...
- Spring :Spring AOP 中的一些术语
1.美图 2.概述 2.1 连接点(Jointpoint) 连接点(Jointpoint):表示需要在程序中插入横切关注点的扩展点,连接点可能是类初始化.方法执行.方法调用.字段调用或处理异常等等,S ...
- Spring Aop中解析spel表达式,实现更灵活的功能
前言 在Spring Aop中,我们可以拿到拦截方法的参数,如果能结合spel表达式,就能实现更加灵活的功能.典型的实现有Spring的缓存注解: @Cacheable(value = "u ...
- Spring AOP 中 advice 的四种类型 before after throwing advice around
Spring AOP(Aspect-oriented programming) 是用于切面编程,简单的来说:AOP相当于一个拦截器,去拦截一些处理,例如:当一个方法执行的时候,Spring 能够拦截 ...
- java @around_正确理解Spring AOP中的Around advice
Spring AOP中,有Before advice和After advice,这两个advice从字面上就可以很容易理解,但是Around advice就有点麻烦了. 乍一看好像是Before ad ...
最新文章
- Windows 2003 AD升级到 Windows 2008 AD
- 《精通J2EE网络编程》中讲的JNDI 6.3总结
- 技术停滞_检测和测试停滞的流– RxJava常见问题解答
- GO语言学习之路23
- ug12.0安装教程(超级详细安装步骤)
- tableau 地图不显示怎么回事
- 9WinMap 映射
- 对数幅度谱图像matlab,fft2绘制图像的对数幅度谱,比较图像旋转、平移和缩放后的频谱...
- 组学生信| Front Immunol |基于血清蛋白质组早期诊断标志筛选的简单套路
- 抛弃Eclipse,投入IDEA 的独孤求败江湖
- html自动定时弹窗,html网页弹窗代码 setinterval 定时任务啊
- xftp、xshell安装出现1603错误解决,亲测有用
- 【算法leetcode每日一练】面试题 08.04. 幂集
- 记一次逗逼的codecraft算法大赛的参赛经历
- 【项目管理一点通】(44) 用户测试(Alpha测试)
- steam验证登录失败_如何向Steam添加两方面身份验证
- 关闭服务器windows server的IE浏览器的增强安全配置
- 【网络安全】跨站脚本攻击漏洞(了解)
- 实验一.MATLAB求解优化问题
- Rust 引入其他的 rs 文件
热门文章
- 简单典型二阶系统_2021考研概率必看典型例题
- 如何使用BurpSuite
- Flink Standalone模式HA部署
- Git-移动记录仪 贴心小棉袄 reflog
- anime.js 动画_Anime.js –轻量级JavaScript动画库
- IOS开发之酷酷爱魔兽
- 多台电脑共用鼠标键盘(局域网内)
- 安卓简单VMP思路笔记
- 微信小程序快速上手【1】
- Error while executing: npm ERR! D:\Program Files\Git\cmd\git.EXE ls-remote -h -t git://github.com/ad