Spring的LoadTimeWeaver(代码织入)
在Java 语言中,从织入切面的方式上来看,存在三种织入方式:编译期织入、类加载期织入和运行期织入。编译期织入是指在Java编译期,采用特殊的编译器,将切面织入到Java类中;而类加载期织入则指通过特殊的类加载器,在类字节码加载到JVM时,织入切面;运行期织入则是采用CGLib工具或JDK动态代理进行切面的织入。
AspectJ采用编译期织入和类加载期织入的方式织入切面,是语言级的AOP实现,提供了完备的AOP支持。它用AspectJ语言定义切面,在编译期或类加载期将切面织入到Java类中。
AspectJ提供了两种切面织入方式,第一种通过特殊编译器,在编译期,将AspectJ语言编写的切面类织入到Java类中,可以通过一个Ant或Maven任务来完成这个操作;第二种方式是类加载期织入,也简称为LTW(Load Time Weaving)。 (只讲解第二种)
如何使用Load Time Weaving?首先,需要通过JVM的-javaagent参数设置LTW的织入器类包,以代理JVM默认的类加载器;第二,LTW织入器需要一个 aop.xml文件,在该文件中指定切面类和需要进行切面织入的目标类。
下面将通过一个简单的例子在描述如何使用LTW:
例子所作的是记录被调用方法的执行时间和CPU使用率。其实这在实际生产中很有用,与其拉一堆性能测试工具,不如动手做个简单的分析切面,使我们能很快得到一些性能指标。我指的是没有硬性的性能测试需求下。
首先我们编写一个被织入的受体类,也就是被拦截的对象。
- public class DemoBean {
- public void run1() {
- System.out.println("run1...");
- }
- public void run2() throws Exception {
- TimeUnit.SECONDS.sleep(2);
- System.out.println("run2...");
- }
- }
接着,我们编写分析方法执行效率的切面。
- @Aspect
- public class ProfileAspect {
- @Around("profileMethod()")
- public Object profile(ProceedingJoinPoint pjp) throws Throwable {
- StopWatch sw = new StopWatch(getClass().getName());
- try {
- sw.start(pjp.getSignature().getName());
- return pjp.proceed();
- } finally {
- sw.stop();
- System.err.println(sw.prettyPrint());
- }
- }
- @Pointcut("execution(public * org.codetree.core.spring.loadtimeweaver.*.*(..))")
- public void profileMethod() {
- System.out.println("profileMethod..");
- }
- }
aop.xml。这个文件要求放在META-INF/aop.xml路径下,以告知AspectJ Weaver我们需要把ProfilingAspect织入到应用的哪些类中。
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
- <aspectj>
- <weaver>
- <!-- only weave classes in your application-specific packages -->
- <include within="org.codetree.core.spring.loadtimeweaver.*" />
- </weaver>
- <aspects>
- <!-- weave in just these aspects -->
- <aspect name="org.codetree.core.spring.loadtimeweaver.ProfileAspect" />
- </aspects>
- </aspectj>
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-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd">
- <context:load-time-weaver aspectj-weaving="autodetect" />
- <context:component-scan base-package="org.codetree.core.spring.loadtimeweaver"
- use-default-filters="false">
- <context:include-filter type="regex"
- expression="org.codetree.core.spring.loadtimeweaver.*" />
- <context:exclude-filter type="regex"
- expression="org.codetree.core.spring.loadtimeweaver.Main" />
- </context:component-scan>
- </beans>
或者
@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.AUTODETECT)
@EnableAspectJAutoProxy
@ComponentScan
通过 <context:load-time-weaver aspectj-weaving="on" /> 使 spring开启 loadtimeweaver, 注意 aspectj-weaving 有三个选项 : on, off, auto-detect, 如果设置为 auto-detect, spring 将会在 classpath 中查找aspejct 需要的 META-INF/aop.xml, 如果找到则开启 aspectj weaving,这个逻辑在LoadTimeWeaverBeanDefinitionParser#isAspectJWeavingEnabled方法中。
测试类
- public class Main {
- public static void main(String[] args) throws Exception {
- ApplicationContext context = new ClassPathXmlApplicationContext("classpath:/spring/loadtimeweaver/loadtimeweaver.xml");
- DemoBean demoBean = context.getBean(DemoBean.class);
- demoBean.run1();
- demoBean.run2();
- }
- }
结果
- 输出结果如下:
- run1...
- StopWatch 'ProfilingAspect': running time (millis) = 0
- -----------------------------------------
- ms % Task name
- -----------------------------------------
- 0001 100% run1
如果想不加JVM的-javaagent参数可以进行如下替换:
- public class ExtInstrumentationLoadTimeWeaver extends InstrumentationLoadTimeWeaver(默认的weaver) {
- @Override
- public void addTransformer(ClassFileTransformer transformer) {
- try {
- super.addTransformer(transformer);
- } catch (Exception e) {吃掉无关异常不抛出}
- }
- }
spring的配置文件
- <?xml version="1.0" encoding="GBK"?>
- <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"
- xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
- http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<context:load-time-weaver weaver-class="com.shansun.multidemo.spring.ExtInstrumentationLoadTimeWeaver" aspectj-weaving="autodetect" />- <context:component-scan base-package="com.shansun.multidemo"></context:component-scan>
- </beans>
Spring的LoadTimeWeaver(代码织入)的更多相关文章
- Spring的LoadTimeWeaver(代码织入)(转)
https://www.cnblogs.com/wade-luffy/p/6073702.html 在Java 语言中,从织入切面的方式上来看,存在三种织入方式:编译期织入.类加载期织入和运行期织入. ...
- 30个类手写Spring核心原理之AOP代码织入(5)
本文节选自<Spring 5核心原理> 前面我们已经完成了Spring IoC.DI.MVC三大核心模块的功能,并保证了功能可用.接下来要完成Spring的另一个核心模块-AOP,这也是最 ...
- .NET静态代码织入——肉夹馍(Rougamo)
肉夹馍是什么 肉夹馍通过静态代码织入方式实现AOP的组件..NET常用的AOP有Castle DynamicProxy.AspectCore等,以上两种AOP组件都是通过运行时生成一个代理类执行AOP ...
- .NET静态代码织入——肉夹馍(Rougamo) 发布1.1.0
肉夹馍(https://github.com/inversionhourglass/Rougamo)通过静态代码织入方式实现AOP的组件,其主要特点是在编译时完成AOP代码织入,相比动态代理可以减少应 ...
- .NET静态代码织入——肉夹馍(Rougamo) 发布1.2.0
肉夹馍(https://github.com/inversionhourglass/Rougamo)通过静态代码织入方式实现AOP的组件,其主要特点是在编译时完成AOP代码织入,相比动态代理可以减少应 ...
- Spring基础系列--AOP织入逻辑跟踪
原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9619910.html 其实在之前的源码解读里面,关于织入的部分并没有说清楚,那些前置.后 ...
- AOP的核心:代理与织入
分为两步: 1.动态生成代理类: 2.织入: 2.6 织入(Weaving) 织入是将增强添加到目标的具体连接点上的过程 . AOP 织入方式: 方式 实现 应用编译期织入 特殊的 Java 编译器. ...
- Java AOP (1) compile time weaving 【Java 切面编程 (1) 编译期织入】
According to wikipedia aspect-oriented programming (AOP) is a programming paradigm that aims to inc ...
- SpringAOP03 项目脚手架、自定义注解、织入切面、引介增强
1 项目脚手架 利用 Maven 进行创建 1.1 利用IDEA创建一个Maven原型项目 技巧01:原型Maven项目是没有webapp文件夹和resources项目文件夹的,需要自己手动创建:创建 ...
随机推荐
- js注册读秒进度条
转载自://http://blog.csdn.net/wugouzi/article/details/12621385 <head> <meta http-equiv="C ...
- springmvc多文件上传
@RequestMapping(value = "/upload", method = RequestMethod.POST) public void upload(@Reques ...
- 【python】dict4ini和xmltodict模块用途
dict4ini模块:可以读写配置文件 xmltodict模块:将xml和json互相转换 https://pypi.python.org/pypi/xmltodict
- bootstrap弹出提示窗口功能
大家常用弹出提示成功或失败时候喜欢用alert,如果不用这个,写个弹窗又麻烦,bootstrap中就有个方法 alert("操作成功"); commonAlert("操作 ...
- linux vi 中按了ctrl+s后没法退出
linux vi 中按了ctrl+s后无法退出 Linux 中使用vi编辑文件 不小心按了Ctrl + S (习惯了) 结果终端就跟死了一样, 解决办法: Ctrl+Q
- Qt中如何添加.qrc文件
You need a resource file (.qrc) within which you embed the input text file. The input file can be an ...
- 聊聊Android的APK反编译
上一篇<How To Use Proguard in Android APP>介绍了如何对Android进行混淆,现在来对它进行反编译看看,里面有些什么东西. APK文件,其实也是一个压缩 ...
- 关于s:iterator 和s:if 的结合使用
<s:iterator value="list" status="st"> <div class="sidebar-nav" ...
- codevs 1488GangGang的烦恼
题目链接:http://codevs.cn/problem/1488/ 写个高精度大数运算就行 #include<cstdio> #include<iostream> #inc ...
- 启动ip转法功能
这种方法无需重启: [root@ha02 ~]# cat /proc/sys/net/ipv4/ip_forward [root@ha02 ~]# sysctl -w net.ipv4.ip_forw ...