iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >解析SpringBoot中使用LoadTimeWeaving技术实现AOP功能
  • 360
分享到

解析SpringBoot中使用LoadTimeWeaving技术实现AOP功能

2024-04-02 19:04:59 360人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

目录1.SpringBoot aop功能1.1 LTW与不同的切面织入时机1.2 jdk实现LTW的原理1.3 如何在spring中实现LTW2. Springboot中使用LTW实

1.SpringBoot AOP功能

1.1 LTW与不同的切面织入时机

AOP——面向切面编程,通过为目标类织入切面的方式,实现对目标类功能的增强。按切面被织如到目标类中的时间划分,主要有以下几种:

  • 1.运行期织入

这是最常见的,比如在运行期通过为目标类生成动态代理的方式实现AOP就属于运行期织入,这也是Spring AOP中的默认实现,并且提供了两种创建动态代理的方式:JDK自带的针对接口的动态代理和使用CGLib动态创建子类的方式创建动态代理。

  • 2.编译期织入

使用特殊的编译器在编译期将切面织入目标类,这种比较少见,因为需要特殊的编译器的支持。

  • 3.类加载期织入

通过字节码编辑技术在类加载期将切面织入目标类中,这是本篇介绍的重点。它的核心思想是:在目标类的class文件被JVM加载前,通过自定义类加载器或者类文件转换器将横切逻辑织入到目标类的class文件中,然后将修改后class文件交给JVM加载。这种织入方式可以简称为LTW(LoadTimeWeaving)。

1.2 JDK实现LTW的原理

可以使用JKD的代理功能让代理器访问到JVM的底层组件,借此向JVM注册类文件转换器,在类加载时对类文件的字节码进行转换。具体而言,java.lang.instrument包下定义了ClassFileTransfORMer接口,该接口的作用如下面的注释所描述

* An agent provides an implementation of this interface in order
* to transform class files.
* The transformation occurs before the class is defined by the JVM.

可以通过实现该接口,并重写如下抽象方法自定义类文件转换规则

byte[]
transform(  ClassLoader         loader,
            String              className,
            Class<?>            classBeingRedefined,
            ProtectionDomain    protectionDomain,
            byte[]              classfileBuffer)
    throws IllegalClassFormatException;

classfileBuffer是原始类文件对应的字节码数组,返回的byte[]为转化后的字节码数组,如果返回null,则表示不进行字节码处理。

而java.lang.instrument包下的Instrumentation接口则可以将我们自定义的ClassTransFormer向JVM内部的组件进行注册

void
addTransformer(ClassFileTransformer transformer);

在实际使用中,可以通过JVM的-javaagent代理参数在启动时获取JVM内部组件的引用,将ClassFileTransformer实例注册到JVM中,JVM在加载Class文件时,会先调用这个ClassTransformer的transform()方法对Class文件的字节码进行转换,比如织入切面中定义的横切逻辑,实现AOP功能。整个过程可以入下所示

1.3 如何在Spring中实现LTW

Spring中默认通过运行期生成动态代理的方式实现切面的织入,实现AOP功能,但是Spring也可以使用LTW技术来实现AOP,并且提供了细粒度的控制,支持在单个ClassLoader范围内实施类文件转换。

Spring中的org.springframework.instrument.classloading.LoadTimeWeaver接口定义了为类加载器添加ClassFileTransfomer的抽象

* Defines the contract for adding one or more
* {@link ClassFileTransformer ClassFileTransformers} to a {@link ClassLoader}.
*
public interface LoadTimeWeaver {

Spring的LTW支持AspectJ定义的切面,既可以是直接使用AspectJ语法定义的切面,也可以是使用@AspectJ注解,通过java类定义的切面。Spring LTW通过读取classpath下META-INF/aop.xml文件,获取切面类和要被切面织入的目标类的相关信息,通过LoadTimeWeaver在ClassLoader加载类文件时将切面织入目标类中,其工作原理如下所示

Spring中可以通过LoadTimeWeaver将Spring提供的ClassFileTransformer注册到ClassLoader中。在类加载期,注册的ClassFileTransformer读取类路径下META-INF/aop.xml文件中定义的切面类和目标类信息,在目标类的class文件真正被VM加载前织入切面信息,生成新的Class文件字节码,然后交给VM加载。因而之后创建的目标类的实例,就已经实现了AOP功能。

2. Springboot中使用LTW实现AOP的例子

实现一个简单的AOP需求,在方法调用前后打印出开始和结束的日志信息。

相关的Maven依赖和插件

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <configuration>
                <argLine>
                    -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
                    -javaagent:"${settings.localRepository}/org/springframework/spring-instrument/${spring.version}/spring-instrument-${spring.version}.jar"
                    <!-- -Dspring.profiles.active=test-->
                </argLine>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <agent>
                    ${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar
                </agent>
                <agent>
                    ${settings.localRepository}/org/springframework/spring-instrument/${spring.version}/spring-instrument-${spring.version}.jar
                </agent>
            </configuration>
        </plugin>
    </plugins>

</build>

这里通过maven插件的方式为JVM设置代理,通过-javaagent参数指定织入器类包的路径,这样就可以在类加载期将切面织入,更多关于javaagent的知识可以参考javaagent

织入目标类


@Component
public class LtwBean {
    public void test(){
        System.out.println("process.......");
    }
}

只有一个test()方法,通过@Componet注解向容器注册。

切面类


@Aspect
public class LogMethodInvokeAspect {

    @Pointcut("execution(public * com.takumiCX.ltw.*.*(..))")
    public void pointCut(){

    }
    @Around("pointCut()")
    public void advise(ProceedingJoinPoint pjp) throws Throwable {


        Signature signature = pjp.getSignature();
        System.out.println(signature+" start..... ");
        pjp.proceed();
        System.out.println(signature+" end......");
    }
}

@Aspect注解表示这是一个切面类

配置类


@Configuration
@ComponentScan("com.takumiCX.ltw")
@EnableLoadTimeWeaving(aspectjWeaving=AUTODETECT)
public class CustomLtwConfig{
}

通过@@EnableLoadTimeWeaving开启LTW功能,可以通过属性aspectjWeaving指定LTW的开启策略

  1. ENABLED

开启LTW

  1. DISABLED

不开启LTW

  • AUTODETECT

如果类路径下能读取到META-INF/aop.xml文件,则开启LTW,否则关闭

  • 在META-INF文件夹下编写aop.xml文件

aop.xml文件内容

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "Http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>

    <!--要织入切面的目标类-->
    <weaver>
        <include within="com.takumiCX.ltw..*" />
    </weaver>
    <!--切面类-->
    <aspects>
        <aspect name="com.takumiCX.ltw.aspect.LogMethodInvokeAspect" />
    </aspects>
</aspectj>

这样我们的Spring容器就能加载该文件读取到描述目标类和切面类的相关信息,容器在加载目标类的class文件到jvm之前,会将切面类中定义的增强逻辑织入到class文件中,真正加载到jvm中的是织入切面后的class文件,因而通过该class文件创建出的目标类的实例,不需要经过动态代理就能实现AOP相关功能。

测试


@RunWith(SpringRunner.class)
@SpringBootTest(classes ={CustomLtwConfig.class})
public class LTWTest {
    @Autowired
    private LtwBean ltwBean;
    @Test
    public void testLTW() throws InterruptedException {

        ltwBean.test();

    }
}

最后的结果如下

方法调用前后分别记录的开始和结束的日志信息,说明我们的切面成功的织入到了目标类。但是这里可能有一个疑问,这真的是LTW(Load TimeWeaving)通过在类加载期织入切面起到的作用吗?有没有可能是LTW没起作用,是Spring AOP默认通过运行期生成动态代理的方式实现的AOP。
我们的LogMethodInvokeAspect切面类上并没有加@Component注解向容器注册,并且配置类CustomLtwConfig上也没有加@EnableAspectJAutoProxy注解开启Aspectj的运行时动态代理,所以这里基于动态代理的AOP并不会生效。

为了验证我们的想法,将aop.xml文件删除

重新运行测试代码

AOP没起到作用,说明刚才的AOP功能确实是通过LTW技术实现的。

当我们给切面类加上@Component注解,给配置类加上@EnableAspectJAutoProxy


@Aspect
@Component
public class LogMethodInvokeAspect {

@Configuration
@ComponentScan("com.takumiCX.ltw")
@EnableAspectJAutoProxy
@EnableLoadTimeWeaving(aspectjWeaving=AUTODETECT)
public class CustomLtwConfig{
}

再次运行测试类时,发现AOP又生效了,这时候类路径下并没有aop.xml,所以这时候AOP是Spring在运行期通过动态代理的方式实现的。

3. 参考资料

《精通Spring4.x企业应用开发实战》
《spring揭秘》
https://sexycoding.iteye.com/blog/1062372

到此这篇关于SpringBoot中使用LoadTimeWeaving技术实现AOP功能的文章就介绍到这了,更多相关SpringBoot AOP功能内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 解析SpringBoot中使用LoadTimeWeaving技术实现AOP功能

本文链接: https://www.lsjlt.com/news/168033.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 解析SpringBoot中使用LoadTimeWeaving技术实现AOP功能
    目录1.SpringBoot AOP功能1.1 LTW与不同的切面织入时机1.2 JDK实现LTW的原理1.3 如何在Spring中实现LTW2. Springboot中使用LTW实...
    99+
    2024-04-02
  • SpringBoot读写Redis客户端并实现技术切换功能
    目录读写客户端jedis技术SpringBoot整合Redis 读写客户端 首先应该打开redis服务; cd命令进入Redis安装目录下: 进入Redis客户端: redis-c...
    99+
    2023-01-30
    SpringBoot读写Redis客户端 SpringBoot Redis切换
  • SpringBoot开发技巧之使用AOP记录日志示例解析
    目录为什么要用AOP?常用的工作场景必须知道的概念AOP 的相关术语Spring 中使用注解创建切面实战应用-利用AOP记录日志定义日志信息封装统一日志处理切面为什么要用AOP? 答...
    99+
    2024-04-02
  • 使用Spring AOP实现用户操作日志功能
    目录我使用Spring AOP实现了用户操作日志功能需求分析功能实现1、 需要一张记录日志的 Log 表导出的 sql 如下:2、我使用的是 Spring Boot 所以需要引入 s...
    99+
    2024-04-02
  • SpringBoot读写Redis客户端并实现Jedis技术切换功能
    目录读写客户端jedis技术SpringBoot整合Redis 读写客户端 首先应该打开redis服务; cd命令进入Redis安装目录下: 进入Redis客户端: redis-cli.exe -h 127.0.0.1...
    99+
    2023-01-30
    SpringBoot读写Redis客户端 SpringBoot Redis切换
  • springboot使用自定义注解实现aop切面日志
    平时我们在开发过程中,代码出现bug时为了更好的在服务器日志中寻找问题根源,会在接口的首尾打印日志,看下参数和返回值是否有问题。但是手动的logger.info() 去编写时工作量较...
    99+
    2024-04-02
  • 怎么在VUE中使用SpringBoot实现分页功能
    这篇文章给大家介绍怎么在VUE中使用SpringBoot实现分页功能,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。1、效果展示2、VUE代码VUE之视图定义<el-row>   ...
    99+
    2023-06-15
  • SpringBoot使用@Cacheable注解实现缓存功能流程详解
    目录一、Spring从3.1开始支持Cache二、@Cacheable常用属性1、value/cacheNames2、key3、condition4、unless5、keyGener...
    99+
    2023-01-12
    SpringBoot @Cacheable注解 SpringBoot @Cacheable实现缓存
  • 如何在SpringBoot中使用Spring-AOP实现接口鉴权
    目录面向切面编程AOP的底层原理实现AOP的相关术语相关注解以及切入点表达式实现接口鉴权1. 配置yml文件2. 读取账密配置3.编写接口鉴权方法4. 编写AOP5.编写接口测试面向...
    99+
    2024-04-02
  • Java技术中如何实现二维码支付功能?
    随着移动支付的普及,二维码支付成为了一种越来越受欢迎的支付方式。二维码支付是一种便捷、快速、安全的支付方式,已经成为了人们日常生活中不可或缺的一部分。本文将介绍如何使用Java技术实现二维码支付功能。 一、二维码支付的基本原理 二维码支付...
    99+
    2023-08-22
    二维码 spring laravel
  • SpringBoot项目实用功能之实现自定义参数解析器
    核心点 1、实现接口 org.springframework.web.method.support.HandlerMethodArgumentResolver su...
    99+
    2024-04-02
  • PHP+MySQL技术实现购物车功能的实用方法
    购物车是电子商务网站中一个非常重要的功能,它能让用户方便地将自己想要购买的商品添加到购物车中,并随时查看和管理已选择的商品。本文将介绍如何利用PHP和MySQL技术实现购物车功能,让网...
    99+
    2024-04-02
  • 详解SpringBoot中使用RabbitMQ的RPC功能
    一、RabbitMQ的RPC简介 实际业务中,有的时候我们还需要等待消费者返回结果给我们,或者是说我们需要消费者上的一个功能、一个方法或是一个接口返回给我们相应的值,而往往大型的系统...
    99+
    2024-04-02
  • SpringBoot中使用RabbitMQ的RPC功能案例分析
    这篇文章主要讲解了“SpringBoot中使用RabbitMQ的RPC功能案例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“SpringBoot中使用RabbitMQ的RPC功能案例分析...
    99+
    2023-06-25
  • Java中怎么用lambda表达式实现aop切面功能
    这篇“Java中怎么用lambda表达式实现aop切面功能”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Java中怎么用la...
    99+
    2023-06-29
  • 怎么使用MyBatisPlus+SpringBoot实现乐观锁功能
    今天小编给大家分享一下怎么使用MyBatisPlus+SpringBoot实现乐观锁功能的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了...
    99+
    2023-07-05
  • SpringBoot中利用AOP和拦截器实现自定义注解
    目录前言Spring实现自定义注解1.引入相关依赖2.相关类Java实现自定义注解通过Cglib实现通过JDk动态代理实现Cglib和JDK动态代理的区别写在最后前言 最近遇到了这样...
    99+
    2024-04-02
  • 核心技术:J2ME中RMS的使用解析(转)
    核心技术:J2ME中RMS的使用解析(转)[@more@]在J2ME中,RMS作为唯一的永久性存储工具,其重要性是不言而喻的。但是很多刚刚开始学习J2ME的新人总是抱怨在这方面的资料很少,或者是针对性不强。因此,我想把自己在这方面的一些学习...
    99+
    2023-06-03
  • 在Spring中AOP怎么使用注解来实现
    这期内容当中小编将会给大家带来有关在Spring中AOP怎么使用注解来实现,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。spring对AOP的实现提供了很好的支持。下面我们就使用Spring的注解来完成A...
    99+
    2023-05-31
    spring aop
  • SpringBoot实现WEB的常用功能案例详解
    目录前言SpringMVC整合支持Spring MVC自动配置项目基础环境搭建功能扩展实现Spring MVC功能扩展实现Spring整合Servlet三大组件使用注册方式整合使用组...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作