Spring5 底层原理 aop之agent增强(黑马)

aop之agent增强

除了使用 AspectJ AOP 和 Spring AOP 提供的基于动态代理和字节码增强的方式,还可以使用 JVM 级别的 Java Agent 技术进行 AOP 增强。

Java Agent 是一个可以以动态的方式向 JVM 注入字节码的程序,它可以修改正在运行的应用程序的字节码,从而实现对应用程序的增强、监控及调试等功能。通过 Java Agent 技术进行 AOP 增强,可以避免修改源代码的情况,并提供了对所有类和所有方法的增强能力,具有更高的灵活性和可靠性。

代码

A10

package com.itheima;

import com.itheima.service.MyService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

/*
    注意几点
    1. 版本选择了 java 8, 因为目前的 aspectj-maven-plugin 1.14.0 最高只支持到 java 16
    2. 运行时需要在 VM options 里加入 -javaagent:C:/Users/manyh/.m2/repository/org/aspectj/aspectjweaver/1.9.7/aspectjweaver-1.9.7.jar
        把其中 C:/Users/manyh/.m2/repository 改为你自己 maven 仓库起始地址
 */
@SpringBootApplication
public class A10 {

    private static final Logger log = LoggerFactory.getLogger(A10.class);

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(A10.class, args);
        MyService service = context.getBean(MyService.class);

        // ⬇️MyService 并非代理, 但 foo 方法也被增强了, 做增强的 java agent, 在加载类时, 修改了 class 字节码
        log.debug("service class: {}", service.getClass());
        service.foo();

        context.close();

        /*
            学到了什么
            1. aop 的原理并非代理一种, agent 也能, 只要字节码变了, 行为就变了
         */
    }
}

MyAspect

package com.itheima.aop;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Aspect // ⬅️注意此切面并未被 Spring 管理
public class MyAspect {

    private static final Logger log = LoggerFactory.getLogger(MyAspect.class);

    @Before("execution(* com.itheima.service.MyService.*())")
    public void before() {
        log.debug("before()");
    }
}

MyService

package com.itheima.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

@Service
public class MyService {

    private static final Logger log = LoggerFactory.getLogger(MyService.class);

    final public void foo() {
        log.debug("foo()");
        this.bar();  //如果一个方法里面调用了内部方法的调用,代理类不会做增强
    }

    public void bar() {
        log.debug("bar()");
    }
}

xml

 <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

当然这个增强也不依赖于spring,但是我们运行时需要注意下面的问题:
注意几点:

  1. 版本选择了 java 8, 因为目前的 aspectj-maven-plugin 1.14.0 最高只支持到 java 16
  2. 运行时需要在 VM options 里加入 -javaagent:C:/Users/manyh/.m2/repository/org/aspectj/aspectjweaver/1.9.7/aspectjweaver-1.9.7.jar
    把其中 C:/Users/manyh/.m2/repository 改为你自己 maven 仓库起始地址

运行一下其class文件可以看一下,是没有更改代码的,增强的时机是在运行时动态修改字节码
(增强生效,出现一些多出来的下面红框里的东西说明成功了):
在这里插入图片描述
在这里说一下,要是一个方法里调用了另一个该类的方法代理是不会增强的,因为其实是用this调用的,不会走代理:
在这里插入图片描述
想看修改的字节码也可以同过一些工具查看,如arthas工具、

下载好工具后,在arthas-bin目录下调用如下命令启动
在这里插入图片描述
选择我们要连接的项目(需要在运行中的下项目才能看到),这里我们连接第三个
在这里插入图片描述
里面有很多的功能我们 help一下看看,我们要的就是反编译这个功能
在这里插入图片描述
jad 跟上需要反编译的包名即可
在这里插入图片描述
这里就很清除的可以看出为什么会增强了
在这里插入图片描述

总的来说,Java Agent 可以替代更灵活地增强任何已加载的类,适用于分布式 AOP 等更加复杂的应用场景,但需要更多的技术和安全性控制。

在spring中常用的还是代理的方法实现aop

收获💡

  1. 类加载时可以通过 agent 修改 class 实现增强
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
Spring AOP (Aspect Oriented Programming) 是 Spring 框架中的一个模块,它实现了面向切面编程,允许开发者将横切关注点(如事务管理、日志记录、安全检查等)抽取到独立的模块中,从而避免代码重复和提高模块的可维护性。Spring AOP底层原理主要基于以下几个关键概念: 1. **通知(Advice)**: 是 AOP 的核心,它是对目标方法执行前后的行为进行增强的代码片段。Spring 提供了五种类型的通知:前置通知(Before)、后置通知(After)、返回后通知(AfterReturning)、异常通知(AfterThrowing)和最终通知(Around)。 2. **切点(Pointcut)**: 定义了一组相关的通知应该何时何地应用。Spring 使用表达式语言(如`@annotation`, `@execution`, `@target`, `@within`等)来定义切点,匹配方法执行的条件。 3. **连接点(Join Point)**: 是程序执行过程中的一点,是通知被应用的地方。Spring AOP 检查通知的匹配条件并在合适的时候执行。 4. **代理(AOP Proxy)**: Spring AOP 实现了一种特殊的代理机制,为被拦截的目标对象创建一个代理对象。有两种代理模式:JDK 动态代理和 CGLIB 生成的字节码代理。对于接口,使用 JDK 动态代理;对于类,如果目标类没有实现接口或没有 final 方法,使用 CGLIB。 5. **切面(Angle)**: 是一组相关通知的集合,由切点和通知组成。在 Spring 中,切面通过 `@Aspect` 注解声明,`@AspectJ` 是其底层语法支持。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Aholic 冲冲冲

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值