https://www.cnblogs.com/wade-luffy/p/6073702.html

在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>

作者在写AOP对class的所有方法做拦截trace的时候发现嵌套调用的方法无法被拦截,因为在被拦截实体中再调用实体里的其他方法的时候,不是指向代理对象,而是当前对象, 于是找资料,在三种织入方式:编译期织入、类加载期织入和运行期织入,而spring里不管是用动态代理还是cglib都是运行期织入,关于这点美团的trace就是用加载器织入实现

Spring的LoadTimeWeaver(代码织入)(转)的更多相关文章

  1. Spring的LoadTimeWeaver(代码织入)

    在Java 语言中,从织入切面的方式上来看,存在三种织入方式:编译期织入.类加载期织入和运行期织入.编译期织入是指在Java编译期,采用特殊的编译器,将切面织入到Java类中:而类加载期织入则指通过特 ...

  2. 30个类手写Spring核心原理之AOP代码织入(5)

    本文节选自<Spring 5核心原理> 前面我们已经完成了Spring IoC.DI.MVC三大核心模块的功能,并保证了功能可用.接下来要完成Spring的另一个核心模块-AOP,这也是最 ...

  3. .NET静态代码织入——肉夹馍(Rougamo)

    肉夹馍是什么 肉夹馍通过静态代码织入方式实现AOP的组件..NET常用的AOP有Castle DynamicProxy.AspectCore等,以上两种AOP组件都是通过运行时生成一个代理类执行AOP ...

  4. .NET静态代码织入——肉夹馍(Rougamo) 发布1.1.0

    肉夹馍(https://github.com/inversionhourglass/Rougamo)通过静态代码织入方式实现AOP的组件,其主要特点是在编译时完成AOP代码织入,相比动态代理可以减少应 ...

  5. .NET静态代码织入——肉夹馍(Rougamo) 发布1.2.0

    肉夹馍(https://github.com/inversionhourglass/Rougamo)通过静态代码织入方式实现AOP的组件,其主要特点是在编译时完成AOP代码织入,相比动态代理可以减少应 ...

  6. Spring基础系列--AOP织入逻辑跟踪

    原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9619910.html 其实在之前的源码解读里面,关于织入的部分并没有说清楚,那些前置.后 ...

  7. AOP的核心:代理与织入

    分为两步: 1.动态生成代理类: 2.织入: 2.6 织入(Weaving) 织入是将增强添加到目标的具体连接点上的过程 . AOP 织入方式: 方式 实现 应用编译期织入 特殊的 Java 编译器. ...

  8. Java AOP (1) compile time weaving 【Java 切面编程 (1) 编译期织入】

    According to wikipedia  aspect-oriented programming (AOP) is a programming paradigm that aims to inc ...

  9. SpringAOP03 项目脚手架、自定义注解、织入切面、引介增强

    1 项目脚手架 利用 Maven 进行创建 1.1 利用IDEA创建一个Maven原型项目 技巧01:原型Maven项目是没有webapp文件夹和resources项目文件夹的,需要自己手动创建:创建 ...

随机推荐

  1. python可变类型和不可变类型

    原文地址:http://www.cnblogs.com/huamingao/p/5809936.html 可变类型 Vs 不可变类型 可变类型(mutable):列表,字典 不可变类型(unmutab ...

  2. kustomize 模版自由的配置&&自定义kubernetes工具

    kustomize 是一个可以方便我们基于模版配置,自定义kubernetes 的工具,类似kompose,但是个人觉得kompose 更灵活点,而且使用上更方便 安装 mac brew instal ...

  3. The key of real time embedded system

    对于实时嵌入式系统来说,最重要的是每一个进程所需时间的可检测性,可预测性.要不你的实时性是没有办法保证的.有些时候你对一些没有从事过嵌入式开发的人谈这个进程(TASK)设计是按8ms被调度一次,他们会 ...

  4. 01c++学习

    #include"iostream" using namespace std; void main01() { //printf("hello_world\n" ...

  5. str_replace中的匹配空白符,必须用双引号

    例: $minUnit = str_replace(array('\r','\n'),"",$content); 执行上面的语句,你会发现,文本没有任何变化,该换行的地方还是换行. ...

  6. 在sorted range上的操作(includes,set_union,set_intersection,set_difference)

    includes //版本一:用operator <比较元素 template <class InputerIterator1,class InputerIterator2> boo ...

  7. FastAdmin 数据库备份插件更新到 v1.0.4

    FastAdmin 数据库备份插件更新到 v1.0.4 下载地址: https://www.fastadmin.net/store/database.html 更新如下: 修复了忽略列表无效的 Bug ...

  8. webpack 4:默认配置

    webpack 4:默认配置 entry 默认: ./src/index.js(注意: 路径必须带上./): entry: './src/index.js', output 默认最后路径: ./dis ...

  9. CF 666E Forensic Examination——广义后缀自动机+线段树合并

    题目:http://codeforces.com/contest/666/problem/E 对模式串建广义后缀自动机,询问的时候把询问子串对应到广义后缀自动机的节点上,就处理了“区间”询问. 还要处 ...

  10. bzoj 2351 [BeiJing2011]Matrix——二维哈希

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2351 就是先把每行单独从左到右扫着乘一个 b1 哈希起来,然后再按列从上往下乘一个 b2 哈 ...