当前位置: 首页 > news >正文

代理对象中使用this

一、问题引出

业务逻辑层代码

@Service
public class DemoServiceImpl extends ServiceImpl<DemoMapper, Demo> implements DemoService, ApplicationContextAware {

    // 用于从Spring容器中获取指定Bean的对象
    private ApplicationContext applicationContext;

    // 通过ApplicationContextAware接口完成applicationContext对象的注入
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
    
    public void methodC() {
        
        System.out.println("使用this调用结果:");
        this.methodD();

        System.out.println("\n使用Bean对象调用结果:");
        DemoServiceImpl bean = applicationContext.getBean(DemoServiceImpl.class);
        bean.methodD();
    }

    public void methodD() {
        System.out.println("执行D方法……");
    }

}

自定义切面:对DemoServiceImpl方法中的methodD方法进行增强,在前后打印相关内容

@Aspect
@Component
public class CustomAspect {

    @Around("execution(* com.example.service.*.methodD(..))")
    public void aspectMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("aspectMethod before执行……");
        joinPoint.proceed();
        System.out.println("aspectMethod after执行……");
    }
}

测试类

@SpringBootTest
class DemoApplicationTests {

    @Test
    void contextLoads() {
    }

    @Resource
    private DemoService demoService;

    @Test
    void test() throws Exception {
        demoService.methodC();
    }

}

测试结果:

使用this调用结果:
执行D方法……

使用Bean对象调用结果:
aspectMethod before执行……
执行D方法……
aspectMethod after执行……

**疑问:**之前学习的时候不是说this不是哪个对象调用就是哪个对象的引用类型(之间的理解有问题,应该是this始终指向当前对象的实例。在实例方法中,this 指向当前对象的实例;在构造方法中,this 指向正在被构造的对象),现在是通过demoService的代理对象(通过AOP进行增强,Spring在创建Bean对象的时候,会对该对象进行代理增强,并放入到IOC容器中)对methodC方法的调用,然后methodC中又通过this去调用methodD方法,那这个this不就是demoService的代理对象吗?methodD不就应该是代理对象的methodD,即增强后的methodD方法吗,但是实际上确实增强前的MethodD方法。

二、原因分析

首先this是Java语言的一个关键字,指向当前对象的实例:

注意:如果通过代理对象调用方法,this 仍然指向 原始对象,而不是代理对象,因为 this 是 Java 语言的关键字,它的行为是由 Java 语言规范定义的,无法被 Spring 或其他框架修改。

this 的行为在编译期就已经确定,编译器会将 this 替换为当前对象的引用:

public class A {
    public void method() {
        System.out.println("Method called");
    }
 
    public static void main(String[] args) {
        A a = new A();
        a.method();
    }
}

其在编译后等价于:

public class A {
    public void method(A this) {
        System.out.println("Method called");
    }
 
    public static void main(String[] args) {
        A a = new A();
        a.method(a);
    }
}

在实例方法调用时,编译器会隐式地将当前对象的引用作为第一个参数传递给方法,通过查看A对应的字节码可以看到,methodC方法的局部变量表中的第一个参数就是this,因此,this关键字实际上就是一个指向当前对象的隐式参数。

因此在上面的DemoServiceImpl的methodC方法中通过this调用methodD方法的时候,其实就是调用DemoServiceImpl实例对象的methodD方法,而不是Spring AOP代理对象的methodD方法,this 是在编译期确定的,指向 DemoServiceImpl 的实例。而通过Spring AOP创建的代理对象是在 运行时 动态生成的,this 仍然指向原始对象。

我们打一个断点,也可以看到this和bean这两个对象是不一样的,this就是DemoServiceImpl实例对象,而bean是通过Spring AOP增强后的代理对象(使用GCLIB进行代理)

在这里插入图片描述

总结:

  • this 是在编译期确定的:它指向当前对象的实例,无法被运行时修改。
  • 代理对象是运行时生成的:Spring 的代理对象无法改变 this 的行为。

尾言

参考文章
  • https://blog.csdn.net/benxiangsj/article/details/124282800
  • https://blog.csdn.net/weixin_53840353/article/det

相关文章:

  • anolis8.9-k8s1.32-系统基本配置
  • Linux--基本指令2
  • 使用Python简单自动地生成图文并茂的网页文件(WEB数据可视化)
  • C# 类库打包dll文件
  • 操作系统之文件系统
  • 一次有趣的前后端跨越排查
  • MobileViTv3模型详解及代码复现
  • vscode接入ai插件(免费版)
  • 2025.3.1学习内容----网络编程
  • 蓝桥杯 门牌制作
  • 儿童英语启蒙规划
  • 分布式拒绝服务(DDoS)攻击检测系统的设计与实现
  • LeetCode:132. 分割回文串 II(DP Java)
  • 《论数据分片技术及其应用》审题技巧 - 系统架构设计师
  • 入门大模型的学习路线是什么?
  • Rt-thread源码剖析(2)——时钟与定时器
  • CAN总线通信协议学习4——数据链路层之仲裁规则
  • DHCP配置实验
  • 企业建设——控制措施类型
  • 静态时序分中的case analysis传播分析
  • 网站开发 wenzhou/湖南正规seo优化
  • 关键词排名优化易下拉稳定/网站推广优化外链
  • 数据库型网站/企业网络营销推广案例
  • 宣讲家网站两学一做心得体会/seo课程简介
  • 做拼图字的网站/百度关键词搜索排名多少钱
  • 本地顺德网站建设/全网搜索引擎