Spring 高级 AOP 实现之 agent 增强
一、代码
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()"); } }
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 version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.5</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.itheima</groupId> <artifactId>aspectj_02</artifactId> <version>0.0.1-SNAPSHOT</version> <name>aspectj_02</name> <description>aspectj_02</description> <properties> <java.version>8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
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 也能, 只要字节码变了, 行为就变了 */ } }
二、测试
发现确实执行了切面类里面的方法,对目标方法增强了
查看编译后的Class文件,发现Class文件并没有被改动
用Arthas反编译,查看发现 在java类加载阶段改动了目标方法的字节码,从而实现对目标方法的增强