概述
文章目录
- AOP实现之ajc编译器
- AOP实现之agent类加载
- AOP实现之动态代理
- jdk动态代理
- 演示
- 模拟实现动态代理
- 动态生成代理类需要使用到asm的api,这里就不展开了
- Jdk对于反射调用的优化
- cglib动态代理
- 演示
- 模拟实现cglib动态代理
- cglib如果通过MethodProxy使用非反射的方式调用方法
- Spring选择代理
- Spring选择动态代理规则
- 切点匹配
- 从@Aspect到Advisor
- AnnotationAwareAspectJAutoProxyCreator
- 方法findEligibleAdvisors
- 方法wrapIfNecessary
- 代理对象的创建时机
- @Order
- 从高级切面到低级切面
- 将切面统一转换成环绕通知
- 调用执行链
- 总结静态通知调用过程
- 动态通知调用
参考 糖果墙的 黑马程序员Spring视频教程,全面深度讲解spring5底层原理 学习笔记
AOP 底层实现方式之一是代理,由代理结合通知和目标,提供增强功能
除此以外,aspectj 提供了两种另外的 AOP 底层实现:
- 第一种是通过 ajc 编译器在编译 class 类文件时,就把通知的增强功能,织入到目标类的字节码中
- 第二种是通过 agent 在加载目标类时,修改目标类的字节码,织入增强功能
- 作为对比,之前学习的代理是运行时生成新的字节码
简单比较的话:
- aspectj 在编译和加载时,修改目标字节码,性能较高
- aspectj 因为不用代理,能突破一些技术上的限制,例如对构造、对静态方法、对 final 也能增强
- 但 aspectj 侵入性较强,且需要学习新的 aspectj 特有语法,因此没有广泛流行
AOP实现之ajc编译器
使用ajc编译器进行代码增强,首先需要在pom.xml文件中加入ajc编译器插件依赖
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.11</version>
<configuration>
<complianceLevel>1.8</complianceLevel>
<source>8</source>
<target>8</target>
<showWeaveInfo>true</showWeaveInfo>
<verbose>true</verbose>
<Xlint>ignore</Xlint>
<encoding>UTF-8</encoding>
</configuration>
<executions>
<execution>
<goals>
<!-- use this goal to weave all your main classes -->
<goal>compile</goal>
<!-- use this goal to weave all your test classes -->
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
加入aspectjweaver的依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
需要增强的类MyService
@Slf4j
public class MyService {
public void foo() {
log.debug("foo()");
}
}
切面类MyAspect,编写execution表达式,对MyService类的foo()方法进行增强
@Aspect // ⬅️注意此切面并未被 Spring 管理,本项目pom文件中根本没有引入spring的相关类
public class MyAspect {
private static final Logger log = LoggerFactory.getLogger(MyAspect.class);
@Before("execution(* top.jacktgq.service.MyService.foo())")
public void before() {
log.debug("before()");
}
}
测试代码
public class Aop_Aspectj_Test {
@Test
public void testAopAjc() {
new MyService().foo();
}
}
-
可以看到没有引入任何跟spring框架相关的包,MyService类是通过直接new()的方式获得的,所以也就不存在使用了动态代理的说法了
-
打开编译后的MyService.class文件,双击以后idea会反编译该字节码文件,可以看到foo()方法体的开头加了一行代码,这就是增强的代码,这是ajc编译器在编译MyService类的时候为我们添加的代码,这是一种编译时的增强。
AOP实现之agent类加载
需要依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
需要增加的类MyService
@Slf4j
public class MyService {
public void foo() {
log.debug("foo()");
bar();
}
public void bar() {
log.debug("bar()");
}
}
切面类MyAspect,编写execution表达式,对MyService类的foo()方法进行增强
@Aspect // ⬅️注意此切面并未被 Spring 管理,本项目pom文件中根本没有引入spring的相关类
@Slf4j
public class MyAspect {
@Before("execution(* top.jacktgq.service.MyService.*())")
public void before() {
log.debug("before()");
}
}
测试代码
public class Aop_agent_Test {
@Test
public void testAopAgent() throws Exception {
MyService myService = new MyService();
myService.foo();
System.in.read();
}
}
运行时需要在 VM options 里加入 -javaagent:D:同步空间repositoryorgaspectjaspectjweaver1.9.7aspectjweaver-1.9.7.jar把其中 D:同步空间repository 改为你自己 maven 仓库起始地址
注:还需要在resources/META-INF目录下建一个aop.xml配置文件,内容如下,aspectj会自动扫描到这个配置文件,不加这个配置文件不会出效果。
<aspectj>
<aspects>
<aspect name="top.jacktgq.aop.MyAspect"/>
<weaver options="-verbose -showWeaveInfo">
<include within="top.jacktgq.service.MyService"/>
<include within="top.jacktgq.aop.MyAspect"/>
</weaver>
</aspects>
</aspectj>
总结:
-
可以看到没有引入任何跟spring框架相关的包,MyService类是通过直接new()的方式获得的,所以也就不存在使用了动态代理的说法了
-
打开编译后的MyService.class文件,双击以后idea会反编译该字节码文件,可以看到foo()方法体中并没有添加多余的代码,所以就不是编译时增强了,而是类加载的时候增强的,这里可以借助阿里巴巴的Arthas工具,下载地址:https://arthas.aliyun.com/doc/en/download.html,解压以后进入到arthas的bin目录下,启动黑窗口,输入java -jar .arthas-boot.jar,在输出的java进程列表里面找到我们要连接的进程,输入对应进程的序号,我这里是4,连接上以后会打印ARTHAS的logo
再输入jad top.jacktgq.service.MyService反编译内存中的MyService类
可以看到foo()和bar()方法体的第一行都加了一行代码,这就说明通过添加虚拟机参数-javaagent的方式可以在类加载的时候对代码进行增强。
AOP实现之动态代理
jdk动态代理
演示
public class ProxyJdkTest {
public static void main(String[] args) {
Dog dog = new Dog();
// 用于加载在运行期间生成的字节码
ClassLoader classLoader = ProxyJdkTest.class.getClassLoader();
Animal proxyDog = (Animal) Proxy.newProxyInstance(classLoader, new Class[]{Animal.class}, (proxy, method, args1) -> {
System.out.println("Before");
Object result = method.invoke(dog, args1);
System.out.println("After");
return result;
});
proxyDog.run();
}
interface Animal {
void run();
}
static class Dog implements Animal {
@Override
public void run() {
System.out.println("Dog is running.");
}
}
}
运行结果
Jdk动态代理要求目标必须实现接口,代理类与被代理类是平级兄弟关系
模拟实现动态代理
准备好一个接口Animal和一个目标代理类Dog
public interface Animal {
void run();
int eat();
}
public class Dog implements Animal {
@Override
public void run() {
System.out.println("Dog is running.");
}
@Override
public int eat() {
System.out.println("Dog is eating");
return 0;
}
}
手动创建一个类叫做 P r o x y 0 ,假装这是编译时期生成的并且定义一个 I n v o c a t i o n H a n d l e r 置于 Proxy0,假装这是编译时期生成的 并且定义一个InvocationHandler置于 Proxy0,假装这是编译时期生成的并且定义一个InvocationHandler置于Proxy0内部,用于提供给使用者使用以灵活编写增强逻辑
public class $Proxy0 implements Animal {
static Method runMethod;
static Method eatMethod;
static {
try {
runMethod = Animal.class.getMethod("run");
eatMethod = Animal.class.getMethod("eat");
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
public $Proxy0(InvocationHandler invocationHandler) {
this.invocationHandler = invocationHandler;
}
private final InvocationHandler invocationHandler;
@Override
public void run() {
try {
invocationHandler.invoke(this, runMethod, new Object[0]);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public int eat() {
Object result;
try {
result = invocationHandler.invoke(this, eatMethod, new Object[0]);
} catch (Exception e) {
throw new RuntimeException(e);
}
return (int) result;
}
}
public interface InvocationHandler {
Object invoke(Object proxy, Method method, Object[] args) throws Exception;
}
测试代码
public class ProxyJdkSimulation {
public static void main(String[] args) {
Dog dog = new Dog();
// 模拟Jdk动态代理
Animal proxyDog = new $Proxy0((proxy, method, args1) -> {
System.out.println("Before");
Object result = method.invoke(dog, args1);
System.out.println("After");
return result;
});
proxyDog.eat();
proxyDog.run();
}
}
测试结果
动态生成代理类需要使用到asm的api,这里就不展开了
Jdk对于反射调用的优化
在jdk代理中调用方法使用到的method.invoke()是通过反射实现的,我们知道反射的效率比较低
循环调用method.invoke17次,能够发现前16次都是通过NativeMethodAccessorImpl实现的,第17次通过一个动态生成的GeneratedMethodAccessor2,优化为非反射调用
cglib动态代理
演示
cglib动态代理是通过生成被代理类的子类,子类重写被代理类的方法实现的
因此要求被代理类不能被final修饰,待增强方法也不能被final修饰
cglib动态代理的增强过程有method和methodProxy两个参数,他们可以做到相同的效果,但是method.invoke()是通过反射的方式调用,methodProxy不是通过反射,所以效率要比method高
methodProxy有invoke和invokeSuper两个方法
methodProxy.invoke(targe, args)方法是Spring使用的
methodProxy.invokeSuper(proxy, args)方法不需要被代理类作为参数
public class ProxyCglibTest {
public static void main(String[] args) {
Dog dog = new Dog();
Dog proxyDog = (Dog) Enhancer.create(Dog.class, (MethodInterceptor) (proxy, method, args1, methodProxy) -> {
System.out.println("Before");
// Object result = method.invoke(dog, args1);
// Object result = methodProxy.invoke(dog, args1);
Object result = methodProxy.invokeSuper(proxy, args1);
System.out.println("After");
return result;
});
proxyDog.run();
}
static class Dog {
public void run() {
System.out.println("Dog is running.");
}
}
}
控制台输出
模拟实现cglib动态代理
cglib动态代理其实跟jdk的很相似
不同在于代理类中除了带有增强功能的方法之外,还需要带有原始功能的方法,以用于创建methodProxy对象
public class Target {
public void save() {
System.out.println("save()");
}
public void save(int i) {
System.out.println("save(int i)");
}
public void save(long j) {
System.out.println("save(long j)");
}
}
public class Proxy extends Target {
private static Method save0Method;
private static Method save1Method;
private static Method save2Method;
private static MethodProxy save0MethodProxy;
private static MethodProxy save1MethodProxy;
private static MethodProxy save2MethodProxy;
static {
try {
save0Method = Target.class.getMethod("save");
save1Method = Target.class.getMethod("save", int.class);
save2Method = Target.class.getMethod("save", long.class);
save0MethodProxy = MethodProxy.create(Target.class, Proxy.class, "()V", "save", "saveSuper");
save1MethodProxy = MethodProxy.create(Target.class, Proxy.class, "(I)V", "save", "saveSuper");
save2MethodProxy = MethodProxy.create(Target.class, Proxy.class, "(J)V", "save", "saveSuper");
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
private MethodInterceptor methodInterceptor;
public Proxy(MethodInterceptor methodInterceptor) {
this.methodInterceptor = methodInterceptor;
}
/**
* 原始功能的方法
*/
public void saveSuper() {
super.save();
}
public void saveSuper(int i) {
super.save(i);
}
public void saveSuper(long j) {
super.save(j);
}
/**
* 以下是带有增强功能的方法
*/
@Override
public void save() {
try {
methodInterceptor.intercept(this, save0Method, null, save0MethodProxy);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
@Override
public void save(int i) {
try {
methodInterceptor.intercept(this, save1Method, new Object[]{i}, save1MethodProxy);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
@Override
public void save(long j) {
try {
methodInterceptor.intercept(this, save2Method, new Object[]{j}, save2MethodProxy);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}
测试代码
public class CglibProxySimulation {
public static void main(String[] args) {
Target target = new Target();
Proxy targetProxy = new Proxy((p, method, objects, methodProxy) -> {
System.out.println("Before");
// return method.invoke(target, objects);
// return methodProxy.invoke(target, objects);
return methodProxy.invokeSuper(p, objects);
});
targetProxy.save();
targetProxy.save(1);
targetProxy.save(2L);
}
}
cglib如果通过MethodProxy使用非反射的方式调用方法
在MethodInterceptor中如果调用了methodProxy.invoke()或methodProxy.invokeSuper()方法,都会生成一个FastClass子类的动态代理类来使用非反射的方式调用
- TargetFastClass
假设methodProxy.invoke()时生成的代理类叫做TargetFastClass,那么这个类内部大概是这样的
public class TargetFastClass {
static Signature signature0 = new Signature("save", "()V");
static Signature signature1 = new Signature("save", "(I)V");
static Signature signature2 = new Signature("save", "(J)V");
public Object invoke(int index, Object target, Object[] args) throws InvocationTargetException {
if (index == 0) {
((Target) target).save();
return null;
}
if (index == 1) {
((Target) target).save((int) args[0]);
return null;
}
if (index == 2) {
((Target) target).save((long) args[0]);
return null;
}
throw new RuntimeException("No such method");
}
public int getIndex(Signature signature) {
if (signature.equals(signature0)) {
return 0;
}
if (signature.equals(signature1)) {
return 1;
}
if (signature.equals(signature2)) {
return 2;
}
return -1;
}
}
* getIndex方法根据方法的标签判断得到当前方法在内部定义的序号
* 然后fastClass内部会将getIndex拿到的序号传递到方法invoke中,根据这个序号就可以使用非反射的方式调用方法了。
- ProxyFastClass
这个类是针对代理类使用的,内部同TargetFastClass逻辑类似,不同之处在于标签记录的是原始功能的方法(即前面的saveSuper()那几个方法),invoke方法也是调用代理类的原始功能方法,因为如果调用增强功能的方法,就会不断进入MethodInterceptor.intercept开始死循环
Spring选择代理
Spring在使用动态代理的时候会在不同情况下使用jdk亦或是cglib的动态代理
准备一个切面(一个通知+一个切点),使用Spring提供的ProxyFactory生成一个代理类,打印查看这个代理类是什么方式生成的
导入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
public class SpringChooseProxyDemo {
public static void main(String[] args) {
// 2. 准备一个切点
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution(* foo())");
// 1. 准备一个通知
MethodInterceptor methodInterceptor = invocation -> {
System.out.println("Before");
Object result = invocation.proceed();
System.out.println("After");
return result;
};
// 3. 将通知和切点整合成一个切面
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, methodInterceptor);
// 4. 通过ProxyFactory生成代理类
ProxyFactory proxyFactory = new ProxyFactory();
Target target = new Target();
proxyFactory.setTarget(target);
proxyFactory.addAdvisor(advisor);
I1 proxy = (I1) proxyFactory.getProxy();
System.out.println("proxy.class ======== " + proxy.getClass());
proxy.foo();
System.out.println("-----------");
proxy.bar();
}
static class Target implements I1 {
@Override
public void foo() {
System.out.println("foo");
}
@Override
public void bar() {
System.out.println("bar");
}
}
interface I1 {
void foo();
void bar();
}
}
执行结果
可以看出这里是通过cglib实现的动态代理
Spring选择动态代理规则
ProxyFactory有一个属性叫做proxyTargetClass,默认情况下proxyTargetClass = false;
- 当proxyTargetClass = false, 若目标类实现了接口,使用jdk动态代理
- 当proxyTargetClass = false, 若目标类没有实现接口,使用cglib动态代理
- 当proxyTargetClass = true,则总是使用cglib动态代理
但是前面并没有把proxyTargetClass改成true,并且Target类也实现了接口I1,为什么还是使用了cglib动态代理呢,那是因为我们需要主动告诉proxyFactory目标类实现了什么接口
proxyFactory.setInterfaces();
切点匹配
前面提到的AspectJExpressionPointcut能够匹配切点,其实是实现了MethodMatcher接口的matches方法,根据matches的返回值是否为true来判断是否匹配上
现在就可以通过实现一个MethodMatcher接口,定义@Transactional注解的切点规则
public class MethodMatch{
public static void main(String[] args) throws NoSuchMethodException {
StaticMethodMatcher methodMatcher = new StaticMethodMatcher() {
@Override
public boolean matches(Method method, Class<?> targetClass) {
MergedAnnotations annotations = MergedAnnotations.from(method);
if (annotations.isPresent(Transactional.class)) {
return true;
}
annotations = MergedAnnotations.from(targetClass, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY);
return annotations.isPresent(Transactional.class);
}
};
System.out.println(methodMatcher.matches(Target1.class.getMethod("foo"), Target1.class));
System.out.println(methodMatcher.matches(Target1.class.getMethod("bar"), Target1.class));
System.out.println(methodMatcher.matches(Target2.class.getMethod("foo"), Target2.class));
System.out.println(methodMatcher.matches(Target3.class.getMethod("foo"), Target3.class));
}
static class Target1 {
@Transactional
public void foo() {
}
public void bar() {
}
}
@Transactional
static class Target2 {
public void foo() {
}
}
@Transactional
interface T {
}
static class Target3 implements T {
public void foo() {
}
}
}
控制台输出
从@Aspect到Advisor
AnnotationAwareAspectJAutoProxyCreator
AnnotationAwareAspectJAutoProxyCreator是一个Bean后处理器,Spring容器能够获取到配置的切面信息,跟它的存在息息相关
AnnotationAwareAspectJAutoProxyCreator的发挥作用的时机
类:创建 -> (发挥作用)依赖注入 -> 初始化(发挥作用)
方法findEligibleAdvisors
AnnotationAwareAspectJAutoProxyCreator中有两个很重要的方法,一个是它的父类AbstractAdvisorAutoProxyCreator的findEligibleAdvisors,这个方法可以查询容器中有哪些切面是与指定的类有关系的。
下面模拟使用AnnotationAwareAspectJAutoProxyCreator,通过反射的方式调用findEligibleAdvisors方法,查看哪些切面与Target1或Target2有关系。
public class Demo {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("aspect1", Aspect1.class);
context.registerBean("config", Config.class);
context.registerBean(ConfigurationClassPostProcessor.class);
context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);
context.refresh();
AnnotationAwareAspectJAutoProxyCreator autoProxyCreator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
Method findEligibleAdvisors = AbstractAdvisorAutoProxyCreator.class.getDeclaredMethod("findEligibleAdvisors", Class.class, String.class);
findEligibleAdvisors.setAccessible(true);
List<Advisor> advisors = (List<Advisor>) findEligibleAdvisors.invoke(autoProxyCreator, Target1.class, "target1");
advisors.forEach(System.out::println);
}
static class Target1 {
public void foo() {
System.out.println("Target1 foo");
}
}
static class Target2 {
public void bar() {
System.out.println("Target2 bar");
}
}
@Aspect
static class Aspect1 {
@Before("execution(* foo())")
public void before() {
System.out.println("Aspect1 before");
}
@After("execution(* foo())")
public void after() {
System.out.println("Aspect1 after");
}
}
@Configuration
static class Config {
@Bean
public DefaultPointcutAdvisor pointcutAdvisor(MethodInterceptor methodInterceptor) {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution(* foo())");
return new DefaultPointcutAdvisor(pointcut, methodInterceptor);
}
@Bean
public MethodInterceptor methodInterceptor() {
return invocation -> {
System.out.println("Config before");
return invocation.proceed();
};
}
}
}
当findEligibleAdvisors的目标是Target1的时候,控制台打印
org.springframework.aop.interceptor.ExposeInvocationInterceptor.ADVISOR
org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [com.ysatnaf.spring_learning.aop.from_aspect_to_advisor.Demo$Config$$Lambda$56/580871917@7d8704ef]
InstantiationModelAwarePointcutAdvisor: expression [execution(* foo())]; advice method [public void com.ysatnaf.spring_learning.aop.from_aspect_to_advisor.Demo$Aspect1.before()]; perClauseKind=SINGLETON
InstantiationModelAwarePointcutAdvisor: expression [execution(* foo())]; advice method [public void com.ysatnaf.spring_learning.aop.from_aspect_to_advisor.Demo$Aspect1.after()]; perClauseKind=SINGLETON
是Target2的时候,控制台打印为空
方法wrapIfNecessary
该方法是AnnotationAwareAspectJAutoProxyCreator的父类AbstractAutoProxyCreator的方法。
该方法内部会调用方法findEligibleAdvisors,根据返回的advisor数量,来判断是否需要为目标对象生成代理对象。如果没有切面与目标对象相关,那么就返回目标对象,如果有切面,那么生成代理类
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("aspect1", Aspect1.class);
context.registerBean("config", Config.class);
context.registerBean(ConfigurationClassPostProcessor.class);
context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);
context.refresh();
AnnotationAwareAspectJAutoProxyCreator autoProxyCreator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
Method wrapIfNecessary = AbstractAutoProxyCreator.class.getDeclaredMethod("wrapIfNecessary", Object.class, String.class, Object.class);
wrapIfNecessary.setAccessible(true);
Object target1 = wrapIfNecessary.invoke(autoProxyCreator, new Target1(), "target1", "target1");
Object target2 = wrapIfNecessary.invoke(autoProxyCreator, new Target2(), "target2", "target2");
System.out.println("target1:" + target1.getClass());
System.out.println("target2:" + target2.getClass());
}
输出台打印,
因为Target1有被切面切到,所以生成了代理类,而Target2没有被切面切到,所以没有生成代理类。
代理对象的创建时机
正常执行下来代理对象是在对象初始化之后才被创建
但是如果有循环依赖,就会在依赖注入之前创建
假设A依赖B,B又依赖A,在A的创建过程中 依赖注入B的时候会先去创建对象B,但是因为B也依赖了A,这时候就会先把A的代理对象创建出来放到二级缓存中,然后B创建完成,A才能拿到B的对象进行依赖注入
也就是说依赖注入的是代理对象
注意:依赖注入和初始化过程不应该被增强,仍应该被施加于原始对象上
@Order
可以通过将@Order注解标注在高级切面(被@Aspect标注的类)上控制切面的顺序
低级切面是通过setOrder()进行控制
order数值越大优先级越低,默认是最大的
从高级切面到低级切面
在查找切面的过程中,如果遇到了高级切面,那么会通过解析把高级切面转换成低级切面,最后放在一个List里
以解析@Before为例
将切面统一转换成环绕通知
拿到所有切面之后会将他们都统一转换成环绕通知MethodInvocation
打印,查看转换前后的类型
可以看到AspectJMethodBeforeAdvice转成了MethodBeforeAdviceInterceptor
AspectJAfterReturningAdvice转化成AfterReturningAdviceInterceptor
AspectJAroundAdvice没有转换,因为它本身就是环绕通知
转换过程采用了适配器模式
调用执行链
调用链List的执行过程是一个执行链
在最前面需要添加一个环绕通知叫做ExposeInvocationInterceptor,它的作用就是把一个MethodInvocation放入当前线程以供后续的切面使用。
通过ReflectiveMethodInvocation执行
最后执行每一个环绕通知,其实是采用了递归的方式
- before1
- before2
- target.method.invoke
- after2
- after1
- 模拟调用链
总结静态通知调用过程
- 分析执行类是否需要生成代理类
- 获取所有的切面
- 把高级切面转换成低级切面
- 把所有的通知转换成环绕通知
- 调用执行链,在这之前需要把一个MethodInvocation放入当前线程
动态通知调用
动态通知调用指的是需要传递参数的通知,没有参数的通知因为可以直接执行增强逻辑所以叫做静态通知,相对于没有参数的通知来说,需要记录切点的信息以便于后续解析参数
下图中就是一个动态通知
动态通知调用过程和静态的基本一样
唯一不同的地方就在于factory.getInterceptorsAndDynamicInterceptionAdvice(转换成环绕通知)时,会在List中新增一个叫做InterceptorAndDynamicMethodMatcher,这个动作其实在方法名中DynamicInterception体现了。
InterceptorAndDynamicMethodMatcher包含了两个成员变量,一个是环绕通知,一个是MethodMatcher
通过反射的方式打印InterceptorAndDynamicMethodMatcher内部包含的信息
可以看到包含了切点信息和通知类型,切点信息就可以用于解析动态参数
最后
以上就是重要啤酒为你收集整理的Spring5底层原理 学习笔记(二)AOP篇AOP实现之ajc编译器AOP实现之agent类加载AOP实现之动态代理Spring选择代理从@Aspect到Advisor的全部内容,希望文章能够帮你解决Spring5底层原理 学习笔记(二)AOP篇AOP实现之ajc编译器AOP实现之agent类加载AOP实现之动态代理Spring选择代理从@Aspect到Advisor所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复