09-AOP

Aspect

定义切面(切面=切入点+通知)

@Component   // 交由spring管理
@Aspect  // 切面
public class MyAspect {

    // 切入点  所有foo方法
    @Before("execution(* foo(..))")
    public void before() {
        // 通知
        System.out.println("前置通知");
    }

    @After("execution(* foo(..))")
    public void after() {
        // 通知
        System.out.println("后置通知");
    }

}

待增强的方法(被代理的目标对象)

@Component
public class MyService {

    public void foo() {
        System.out.println("MyService.foo");
    }

}

测试

ConfigurableApplicationContext applicationContext = SpringApplication.run(TestAspect.class, args);
MyService myService = applicationContext.getBean(MyService.class);
myService.foo();

Advisor

待增强的方法(被代理的目标对象)

interface I1 {
    void foo();

    void bar();
}

class Target1 implements I1 {
    @Override
    public void foo() {
        System.out.println("Target1.foo");
    }

    @Override
    public void bar() {
        System.out.println("Target1.bar");
    }
}

class Target2 {
    public void foo() {
        System.out.println("Target2.foo");
    }

    public void bar() {
        System.out.println("Target2.bar");
    }
}

测试

// 1. 定义切入点  表达式切入点
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution(* foo())");

// 2. 定义通知
MethodInterceptor advice = new MethodInterceptor() {
    @Nullable
    @Override
    public Object invoke(@Nonnull MethodInvocation invocation) throws Throwable {
        System.out.println("before...");
        // 调用目标方法
        Object ret = invocation.proceed();
        System.out.println("after...");
        return ret;
    }
};

// 3. 定义切面    封装切入点与通知
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, advice);

// 4. 创建代理
Target1 target = new Target1();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
proxyFactory.setProxyTargetClass(true);
proxyFactory.setInterfaces(target.getClass().getInterfaces());
// 添加切面
proxyFactory.addAdvisor(advisor);

/**
 * 生成代理的方式是jdk还是cglib  由spring内部决定
 * 规则如下:
 * a.  proxyTargetClass为false (ProxyConfigs属性 proxyFactory.setProxyTargetClass(false))
 *     目标对象实现了接口 (proxyFactory.setInterfaces(target.getClass().getInterfaces());)   【使用JDK】
 * b. proxyTargetClass为false 目标对象没有实现接口   【使用cglib】
 * c. proxyTargetClass为true   【使用cglib】    @EnableAspectJAutoProxy(exposeProxy = true, proxyTargetClass = true)
 */

Target1 proxy = (Target1) proxyFactory.getProxy();
/**
 * JDK:
 * class com.you.meet.nice.test.web.spring.aop.spring.$Proxy2
 * CGLIB:
 * class com.you.meet.nice.test.web.spring.aop.spring.Target2$$EnhancerBySpringCGLIB$$818f8618
 */
System.out.println("proxyClass = " + proxy.getClass());
proxy.foo();
proxy.bar();

Aspect与Advisor关系

:::info
spring定义切面两种方式 aspect/advisor
1. aspect可以定义多组通知和切入点,advisor只能定义一组通知和切入点
2. aspect底层还是advisor
:::

切入点匹配

准备目标对象

static class T1 {

    @Transactional
    public void foo() {
    }

    public void bar() {
    }

}

@Transactional
static class T2 {
    public void foo() {

    }

    public void bar() {

    }
}

@Transactional
interface I1 {
    void foo();
}

static class T3 implements I1 {
    @Override
    public void foo() {

    }

    public void bar() {

    }
}

AspectJExpressionPointcut匹配

AspectJExpressionPointcut pt = new AspectJExpressionPointcut();
// 匹配方法
pt.setExpression("execution(* foo())");
System.out.println("匹配方法:" + pt.matches(T1.class.getMethod("foo"), T1.class));  // true
System.out.println("匹配方法:" + pt.matches(T1.class.getMethod("bar"), T1.class));   // false

pt = new AspectJExpressionPointcut();
// 匹配注解
pt.setExpression("@annotation(org.springframework.transaction.annotation.Transactional)");
System.out.println("匹配方法注解:" + pt.matches(T1.class.getMethod("foo"), T1.class));  // true
System.out.println("匹配方法注解:" + pt.matches(T1.class.getMethod("bar"), T1.class));   // false

StaticMethodMatcherPointcut匹配

:::info
那Spring底层是不是就是使用AspectJExpressionPointcut在匹配事务注解的呢?
答案:不是的
因为事务注解不仅可以放在方法上,还可以放在类上,接口上(表示类/接口实现类里的所有方法都包含事务)
而AspectJExpressionPointcut只能匹配方法,Spring底层是使用StaticMethodMatcherPointcut匹配的
:::

StaticMethodMatcherPointcut transPointcut = new StaticMethodMatcherPointcut() {
    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        // 先判断方法上是否包含事务注解
        MergedAnnotations mergedAnnotations = MergedAnnotations.from(method);
        if (mergedAnnotations.isPresent(Transactional.class)) {
            return true;
        }
        // 默认只会找当前类的注解   不会查找这个类继承树上其他父类是否存在注解
        // mergedAnnotations = MergedAnnotations.from(targetClass);
        // 找到这个类以及继承树上是否有此注解
        mergedAnnotations = MergedAnnotations.from(targetClass, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY);
        if (mergedAnnotations.isPresent(Transactional.class)) {
            return true;
        }
        return false;
    }
};

System.out.println("匹配方法/类注解:" + transPointcut.matches(T1.class.getMethod("foo"), T1.class));  // true
System.out.println("匹配方法/类注解:" + transPointcut.matches(T1.class.getMethod("bar"), T1.class));   // false

System.out.println("匹配方法/类注解:" + transPointcut.matches(T2.class.getMethod("foo"), T2.class));  // true
System.out.println("匹配方法/类注解:" + transPointcut.matches(T2.class.getMethod("bar"), T2.class));   // true

System.out.println("匹配方法/类注解:" + transPointcut.matches(T3.class.getMethod("foo"), T3.class));  // true
System.out.println("匹配方法/类注解:" + transPointcut.matches(T3.class.getMethod("bar"), T3.class));   // true

AnnotationAwareAspectJAutoProxyCreator

Spring是如何生成代理类的?

准备目标对象

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 MethodInterceptor advice1() {
        return new MethodInterceptor() {
            @Nullable
            @Override
            public Object invoke(@Nonnull MethodInvocation invocation) throws Throwable {
                System.out.println("advisor1.invoke before...");
                Object ret = invocation.proceed();
                System.out.println("advisor1.invoke after...");
                return ret;
            }
        };
    }

    @Bean  // 低级切面
    public Advisor advisor1(Advice advice1) {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("execution(* foo())");
        return new DefaultPointcutAdvisor(pointcut, advice1);
    }
}

测试

GenericApplicationContext applicationContext = new GenericApplicationContext();
applicationContext.registerBean("aspect1", Aspect1.class);
applicationContext.registerBean(Config.class);
applicationContext.registerBean(ConfigurationClassPostProcessor.class);
/**
 *  BeanPostProcessor:  找到所有切面  如果是高级切面需要转换为低级切面  最后生成代理对象
 *  初始化后执行
 */
applicationContext.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);
applicationContext.refresh();

重要方法

findEligibleAdvisors:收集适用指定bean的所有切面

AnnotationAwareAspectJAutoProxyCreator proxyCreator = applicationContext.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
// 找到所有有资格的切面  高级切面转换为低级切面
Method findEligibleAdvisorsMethod = AbstractAdvisorAutoProxyCreator.class.getDeclaredMethod("findEligibleAdvisors", Class.class, String.class);
findEligibleAdvisorsMethod.setAccessible(true);
// 收集所有适用Target1的切面
List<Advisor> advisors = (List<Advisor>) findEligibleAdvisorsMethod.invoke(proxyCreator, Target1.class, "target1");
for (Advisor advisor : advisors) {
    // 除了spring内置的ExposeInvocationInterceptor  还有三个切面  高级切面转换为2个低级切面+1个低级切面
    System.out.println("advisor = " + advisor);
}

wrapIfNecessary:生成代理类

Method wrapIfNecessaryMethod = AbstractAutoProxyCreator.class.getDeclaredMethod("wrapIfNecessary", Object.class, String.class, Object.class);
wrapIfNecessaryMethod.setAccessible(true);
// spring使用容器中取  这里直接实例化测试
Object target1 = wrapIfNecessaryMethod.invoke(proxyCreator, new Target1(), "target1", "target1");
Object target2 = wrapIfNecessaryMethod.invoke(proxyCreator, new Target2(), "target2", "target2");
// 匹配到切点表达式  生成cglib代理
System.out.println("target1.getClass() = " + target1.getClass());
// 未匹配到  原对象
System.out.println("target2.getClass() = " + target2.getClass());

((Target1) target1).foo();

代理创建时机

Bean

static class Bean1 {

    public Bean1() {
        System.out.println(this.getClass() + " invoke Bean1.Bean1()");
    }

    @Autowired  // 验证循环依赖
    public void setBean2(Bean2 bean2) {
        System.out.println(this.getClass() + "Bean1.setBean2()->" + bean2.getClass());
    }

    @PostConstruct
    public void init() {
        System.out.println(this.getClass() + " Bean1.init()");
    }

    public void foo() {
        System.out.println("Bean1.foo");
    }

}

static class Bean2 {

    public Bean2() {
        System.out.println(this.getClass() + " invoke Bean2.Bean2()");
    }

    @Autowired
    public void setBean1(Bean1 bean1) {
        // bean1是代理对象
        System.out.println(this.getClass() + " Bean2.setBean1()-> " + bean1.getClass());
    }

    @PostConstruct
    public void init() {
        System.out.println(this.getClass() + " Bean2.init()");
    }

}

配置类

@Configuration
static class Config {

    @Bean
    public MethodInterceptor fooAdvice() {
        return new MethodInterceptor() {
            @Nullable
            @Override
            public Object invoke(@Nonnull MethodInvocation invocation) throws Throwable {
                System.out.println("before...");
                invocation.proceed();
                System.out.println("after...");
                return null;
            }
        };
    }

    @Bean
    public Advisor fooAdvisor(Advice fooAdvice) {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("execution(* foo())");
        return new DefaultPointcutAdvisor(pointcut, fooAdvice);
    }

    @Bean
    public Bean1 bean1() {
        return new Bean1();
    }

    @Bean
    public Bean2 bean2() {
        return new Bean2();
    }

}

测试

GenericApplicationContext applicationContext = new GenericApplicationContext();
applicationContext.registerBean(Config.class);
// 处理注解bean
applicationContext.registerBean(ConfigurationClassPostProcessor.class);
// 处理注解生成代理
applicationContext.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);
// 处理依赖注入
applicationContext.registerBean(AutowiredAnnotationBeanPostProcessor.class);
// 处理初始化@PostConstruct
applicationContext.registerBean(CommonAnnotationBeanPostProcessor.class);
applicationContext.refresh();

Bean1 bean = applicationContext.getBean(Bean1.class);
bean.foo();

总结

实例化 -> () -> 依赖注入 -> 初始化 -> ()
代理的创建时机:

  1. 初始化之后:没有循环依赖
  2. 实例化后,依赖注入之前(有循环依赖) 暂存于二级缓存

依赖注入和初始化不应该被增强,即还是原对象调用

切面顺序

默认顺序

以前面章节AnnotationAwareAspectJAutoProxyCreator中的例子描述,切面的默认顺序是
低级切面(Advisor) > 高级切面(@Aspect)

调整顺序

可以使用@Order注解调整顺序
image.png
image.png

顺序失效情况

DefaultPointcutAdvisor顺序不能使用@Order使用,只能调用advisor.setOrder。
image.png
通知无法控制顺序
image.png

高级切面是怎么转换为低级切面的?

准备高级切面与通知

static class Aspect {

    @Before("execution(* foo())")
    public void before() {
        System.out.println("Aspect.before");
    }

    @Before("execution(* foo())")
    public void before2() {
        System.out.println("Aspect.before2");
    }

    public void after() {
        System.out.println("Aspect.after");
    }

    public void afterReturning() {
        System.out.println("Aspect.afterReturning");
    }

    public void afterThrowing() {
        System.out.println("Aspect.afterThrowing");
    }

    public void around() {
        System.out.println("Aspect.around");
    }

}

static class Target {
    public void foo() {
        System.out.println("Target.foo");
    }
}

测试

// 切面实例工厂
AspectInstanceFactory aif = new SingletonAspectInstanceFactory(new Aspect());
// 切面
List<Advisor> advisorList = new ArrayList<>();
for (Method method : Aspect.class.getDeclaredMethods()) {
    if (method.isAnnotationPresent(Before.class)) {
        // 解析切入点
        String expression = method.getAnnotation(Before.class).value();
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(expression);
        // 前置通知
        AspectJMethodBeforeAdvice beforeAdvice = new AspectJMethodBeforeAdvice(method, pointcut, aif);
        //AspectJAroundAdvice      环绕
        //AspectJAfterReturningAdvice   返回
        //AspectJAfterThrowingAdvice   异常
        //AspectJAfterAdvice   后置
        // 切面
        advisorList.add(new DefaultPointcutAdvisor(pointcut, beforeAdvice));
    }
}

advisorList.forEach(System.out::println);

非环绕通知转换为环绕通知

环绕通知:即实现了MethodInterceptor的通知
环绕通知有:

  • AspectJAroundAdvice
  • AspectJAfterAdvice
  • AspectJAfterThrowingAdvice

非环绕通知有

  • AspectJMethodBeforeAdvice
  • AspectJAfterReturningAdvice
static class Aspect {

    @Before("execution(* foo())")
    public void before() {
        System.out.println("Aspect.before");
    }

    @Before("execution(* foo())")
    public void before2() {
        System.out.println("Aspect.before2");
    }

    public void after() {
        System.out.println("Aspect.after");
    }

    @AfterReturning("execution(* foo())")
    public void afterReturning() {
        System.out.println("Aspect.afterReturning");
    }

    @AfterThrowing("execution(* foo())")
    public void afterThrowing() {
        System.out.println("Aspect.afterThrowing");
    }

    public void around() {
        System.out.println("Aspect.around");
    }

}
// 切面实例工厂
AspectInstanceFactory aif = new SingletonAspectInstanceFactory(new Aspect());
// 切面
List<Advisor> advisorList = new ArrayList<>();
for (Method method : Aspect.class.getDeclaredMethods()) {
    if (method.isAnnotationPresent(Before.class)) {
        // 解析切入点
        String expression = method.getAnnotation(Before.class).value();
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(expression);
        // 前置通知
        AspectJMethodBeforeAdvice beforeAdvice = new AspectJMethodBeforeAdvice(method, pointcut, aif);
        //AspectJAroundAdvice      环绕
        //AspectJAfterReturningAdvice   返回
        //AspectJAfterThrowingAdvice   异常
        //AspectJAfterAdvice   后置
        // 切面
        advisorList.add(new DefaultPointcutAdvisor(pointcut, beforeAdvice));
    } else if (method.isAnnotationPresent(AfterReturning.class)) {
        // 解析切入点
        String expression = method.getAnnotation(AfterReturning.class).value();
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(expression);
        // return通知
        AspectJAfterReturningAdvice afterReturningAdvice = new AspectJAfterReturningAdvice(method, pointcut, aif);
        // 切面
        advisorList.add(new DefaultPointcutAdvisor(pointcut, afterReturningAdvice));
    } else if (method.isAnnotationPresent(AfterThrowing.class)) {
        // 解析切入点
        String expression = method.getAnnotation(AfterThrowing.class).value();
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(expression);
        // 异常通知
        AspectJAfterThrowingAdvice afterThrowingAdvice = new AspectJAfterThrowingAdvice(method, pointcut, aif);
        // 切面
        advisorList.add(new DefaultPointcutAdvisor(pointcut, afterThrowingAdvice));
    }
}
// 转换前
advisorList.forEach(System.out::println);

// 这里会有一个排序操作

// 非环绕通知转换为环绕通知
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new Target());
proxyFactory.addAdvisors(advisorList);

System.out.println("============>");
// 转换为环绕通知
List<Object> dynamicInterceptionAdvice = proxyFactory.getInterceptorsAndDynamicInterceptionAdvice(Target.class.getMethod("foo"), Target.class);
dynamicInterceptionAdvice.forEach(System.out::println);

适配器

这种转换体现了适配器模式的思想

  • MethodBeforeAdviceAdapter

@Before AspectJMethodBeforeAdvice -> MethodBeforeAdviceAdapter

  • AfterReturningAdviceAdapter

@AfterReturning AspectJAfterReturningAdvice -> AfterReturningAdviceInterceptor

调用链执行所有通知以及目标方法

// 非环绕通知转换为环绕通知
Target target = new Target();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
// 将ExposeInvocationInterceptor放入第一个通知  将MethodInvocation放入线程上下文
proxyFactory.addAdvice(ExposeInvocationInterceptor.INSTANCE);
proxyFactory.addAdvisors(advisorList);

System.out.println("============>");
// 转换为环绕通知  适配器模式
Method fooMethod = Target.class.getMethod("foo");
List<Object> dynamicInterceptionAdvice = proxyFactory.getInterceptorsAndDynamicInterceptionAdvice(fooMethod, Target.class);
dynamicInterceptionAdvice.forEach(System.out::println);

// 创建调用链 (执行所有环绕通知和目标方法)
Constructor<ReflectiveMethodInvocation> reflectiveMethodInvocationConstructor = ReflectUtil.getConstructor(ReflectiveMethodInvocation.class, Object.class, Object.class, Method.class, Object[].class,
        Class.class, List.class);
reflectiveMethodInvocationConstructor.setAccessible(true);
ReflectiveMethodInvocation reflectiveMethodInvocation = reflectiveMethodInvocationConstructor.newInstance(
        null, target, fooMethod, new Object[0], Target.class, dynamicInterceptionAdvice
);
/**
 *  会报错:因为其它通知方法里面可能也需要MethodInvocation对象
 *  所以需要使用ExposeInvocationInterceptor将MethodInvocation放到线程上下文
 */
reflectiveMethodInvocation.proceed();

模拟调用链

调用链: 递归+责任链

准备目标以及通知

static class Target {

    public void foo() {
        System.out.println("Target.foo");
    }

}

static class Advice1 implements MethodInterceptor {
    @Nullable
    @Override
    public Object invoke(@Nonnull MethodInvocation invocation) throws Throwable {
        System.out.println("Advice1.invoke before...");
        // 调用下一个通知或者目标方法
        Object ret = invocation.proceed();
        System.out.println("Advice1.invoke after...");
        return ret;
    }
}

static class Advice2 implements MethodInterceptor {
    @Nullable
    @Override
    public Object invoke(@Nonnull MethodInvocation invocation) throws Throwable {
        System.out.println("Advice2.invoke before...");
        Object ret = invocation.proceed();
        System.out.println("Advice2.invoke after...");
        return ret;
    }
}

调用链对象

static class MyMethodInvocation implements MethodInvocation {

    private Object target;  // 1
    private Method targetMethod;
    private Object[] targetArgs;
    private List<MethodInterceptor> methodInterceptorList; // 2
    private int callCount = 1;

    public MyMethodInvocation(Object target, Method method, Object[] args, List<MethodInterceptor> methodInterceptorList) {
        this.target = target;
        this.targetMethod = method;
        this.targetArgs = args;
        this.methodInterceptorList = methodInterceptorList;
    }

    @Nonnull
    @Override
    public Method getMethod() {
        return targetMethod;
    }

    @Nonnull
    @Override
    public Object[] getArguments() {
        return targetArgs;
    }

    @Nullable
    @Override
    public Object proceed() throws Throwable {
        // 如果还有环绕通知 调用环绕通知  没有的话  调用目标方法
        if (callCount > methodInterceptorList.size()) {
            return targetMethod.invoke(target, targetArgs);
        }
        // 逐个递归调用环绕通知  调用次数+1
        MethodInterceptor methodInterceptor = methodInterceptorList.get(callCount - 1);
        callCount++;
        return methodInterceptor.invoke(this);
    }

    @Nullable
    @Override
    public Object getThis() {
        return target;
    }

    @Nonnull
    @Override
    public AccessibleObject getStaticPart() {
        return targetMethod;
    }
}

测试

Target target = new Target();
List<MethodInterceptor> adviceList = CollUtil.newArrayList(new Advice1(), new Advice2());
MyMethodInvocation methodInvocation = new MyMethodInvocation(target, Target.class.getMethod("foo"), new Object[0], adviceList);
methodInvocation.proceed();

动态通知

目标对象与通知

static class Target {

    public void foo(int x) {
        System.out.println("Target.foo.int." + x);
    }

}

@org.aspectj.lang.annotation.Aspect
static class Aspect {

    @Before("execution(* foo(..))")    // 静态通知调用  不需要参数绑定   执行时不需要切点
    public void before() {
        System.out.println("Aspect.before");
    }

    @Before("execution(* foo(..)) && args(x)")   // 动态通知调用  需要进行参数绑定  执行时需要切点对象
    public void before(int x) {
        System.out.println("Aspect.before.int." + x);
    }

}

测试

GenericApplicationContext applicationContext = new GenericApplicationContext();
applicationContext.registerBean(Aspect.class);
applicationContext.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);
applicationContext.refresh();


AnnotationAwareAspectJAutoProxyCreator proxyCreator = applicationContext.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
Method findEligibleAdvisorsMethod = AbstractAdvisorAutoProxyCreator.class.getDeclaredMethod("findEligibleAdvisors", Class.class, String.class);
findEligibleAdvisorsMethod.setAccessible(true);
List<Advisor> advisors = (List<Advisor>) findEligibleAdvisorsMethod.invoke(proxyCreator, TestDynamicAdvice.Target.class, "target");

Target target = new Target();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
proxyFactory.addAdvisors(advisors);

// 获取代理
Object proxy = proxyFactory.getProxy();
Method fooMethod = Target.class.getMethod("foo", int.class);
List<Object> methodInterceptors = proxyFactory.getInterceptorsAndDynamicInterceptionAdvice(fooMethod, Target.class);
for (Object methodInterceptor : methodInterceptors) {
    /**
     * ExposeInvocationInterceptor: 将调用链对象存入线程上下文
     * MethodBeforeAdviceInterceptor  前置通知(已转换环绕通知)
     * InterceptorAndDynamicMethodMatcher 动态通知对象  持有MethodInterceptor(环绕通知) + methodMatcher(切入点) 对象
     */
    System.out.println(methodInterceptor);
}


System.out.println("==============>");

Constructor<ReflectiveMethodInvocation> reflectiveMethodInvocationConstructor = ReflectUtil.getConstructor(ReflectiveMethodInvocation.class, Object.class, Object.class, Method.class, Object[].class,
        Class.class, List.class);
reflectiveMethodInvocationConstructor.setAccessible(true);
ReflectiveMethodInvocation reflectiveMethodInvocation = reflectiveMethodInvocationConstructor.newInstance(
        proxy, target, fooMethod, new Object[]{100}, Target.class, methodInterceptors
);
reflectiveMethodInvocation.proceed();

小结

:::info
有参数绑定的通知调用时还需要切入点,对参数进行匹配和绑定�
动态通知复杂度高,性能要比静态通知要低�
:::

  • 30
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

层巅余落日

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

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

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

打赏作者

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

抵扣说明:

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

余额充值