• Spring(17) AopContext.currentProxy() 类内方法调用切入


    一、简介

    背景:

    在之前 Spring 的 AOP 用法中,只有代理的类才会被切入。例如:我们在 Controller 层调用 Service 的方式时,是可以被切入的。但是如果我们在 Service 层 A 方法中,调用 B 方法,切点切的是 B 方法,那么这时候是不会被切入的。

    解决方案如标题所示,可以使用 AopContext.currentProxy() 来解决。在 A 方法中使用如下方式来调用 B 方法,这样一来,就能切入了:

    import org.springframework.aop.framework.AopContext;
    
    ((Service) AopContext.currentProxy()).B();
    
    • 1
    • 2
    • 3

    二、代码示例

    2.1 接口类

    首先定义一个接口,其中前两个方法内部通过不同方式调用了第三个方法。

    SomeInterface.java

    public interface SomeInterface {
    
        /** 调用方,普通调用 */
        void someMethod();
        /** 调用方,获取代理调用 */
        void someMethodWithProxy();
        /** 被调用方 */
        void anotherMethod();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2.2 接口实现类

    然后我们按照上面描述的关系来编写实现类。

    MyBean.java

    import com.demo.module.test.SomeInterface;
    import org.springframework.aop.framework.AopContext;
    import org.springframework.stereotype.Component;
    
    @Component
    public class MyBean implements SomeInterface {
    
        @Override
        public void someMethod() {
            System.out.println("someMethod...");
            this.anotherMethod();
        }
    
        @Override
        public void someMethodWithProxy() {
            System.out.println("someMethodWithProxy...");
            MyBean myBean = (MyBean) AopContext.currentProxy();
            myBean.anotherMethod();
        }
    
        @Override
        public void anotherMethod() {
            System.out.println("anotherMethod...");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    2.3 AOP切面类

    这里实现了一个切面来增强被调用的方法 anotherMethod()。

    SomeAspect.java

    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Aspect;
    import org.springframework.stereotype.Component;
    
    @Aspect
    @Component
    public class SomeAspect {
    
        @After("execution(* com.demo.impl.MyBean.anotherMethod(..))")
        public void afterAnotherMethod() {
            System.out.println("after anotherMethod");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2.4 启动类(测试)

    注意,这里需要在启动类或者配置类中添加如下注解,不然无法使用 AopContext.currentProxy() 方法来获取代理类。

    @EnableAspectJAutoProxy(exposeProxy = true) // 开启 Spring 注解 AOP 配置的支持
    
    • 1

    不添加会出现如下报错:java.lang.IllegalStateException: Cannot find current proxy: Set ‘exposeProxy’ property on Advised to ‘true’ to make it available…

    Caused by: java.lang.IllegalStateException: Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available, and ensure that AopContext.currentProxy() is invoked in the same thread as the AOP invocation context.
    	at org.springframework.aop.framework.AopContext.currentProxy(AopContext.java:69) ~[spring-aop-5.2.6.RELEASE.jar:5.2.6.RELEASE]
    	at com.demo.module.test.impl.MyBean.someMethodWithProxy(MyBean.java:26) ~[classes/:na]
    
    • 1
    • 2
    • 3

    此外,我们在启动类中注入了一个 CommandLineRunner 类,用于启动后立马执行测试代码。

    DemoApplication.java

    import com.demo.module.test.SomeInterface;
    import org.springframework.boot.CommandLineRunner;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.EnableAspectJAutoProxy;
    
    import javax.annotation.Resource;
    
    @EnableAspectJAutoProxy(exposeProxy = true) // 开启 Spring 注解 AOP 配置的支持
    @SpringBootApplication
    public class DemoApplication {
    
        @Resource
        private SomeInterface someInterface;
    
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    
        @Bean
        public CommandLineRunner commandLineRunner() {
            return args -> {
                System.out.println("===== someMethod ======");
                someInterface.someMethod();
                System.out.println("===== someMethodWithProxy ======");
                someInterface.someMethodWithProxy();
                System.out.println("===== end ======");
            };
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    2.5 执行结果

    执行结果如下,可以看到通过 AopContext.currentProxy() 获取当前类的代理后再调用,可以正常进行 AOP 增强。

    请添加图片描述

    整理完毕,完结撒花~ 🌻





    参考地址:

    1.AopContext.currentProxy(),https://blog.csdn.net/qq_29860591/article/details/108728150

  • 相关阅读:
    python14 字典类型
    安装appnium
    含文档+PPT+源码等]精品基于SSM的农产品交易平台[包运行成功]Java毕业设计SSM项目源码论文
    二氧化钛接枝聚(苯乙烯-二乙烯苯)/马来酸酐多孔纳米复合微球
    百度Apollo自动驾驶
    MCU(单片机)datasheet(规格说明书)
    【机器学习】李宏毅——自监督式学习
    java计算机毕业设计基于ssm的大学生心理健康网站
    狂神——SpringSecurity入门例子(设置不同用户访问权限)
    node express实现json转Excel
  • 原文地址:https://blog.csdn.net/qq_33204709/article/details/133828468