SpringBoot框架:两个方法同时调用时父方法使内部方法的DataSource注解失效的解决办法

一、问题如下:

  使用的是SpringBoot框架:通过AOP和自定义注解完成druid连接池的动态数据源切换(三)中的两个数据库spring_boot_demoother_data

  在UserController中同时调用两个方法getAgeOfUser()getAgeOfUser2(),这里方法里都是使用UserService中的同一方法接收数据。

  不同的是在getAgeOfUser2()上使用了DataSource(DataSourceName.SECOND)自定义注解来切换数据源,当两个方法同时被调用时,代码如下:

package com.example.demo.controller; import com.example.demo.annotation.DataSource; import com.example.demo.enums.DataSourceName; import com.example.demo.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @author 我命倾尘 */ @RestController public class UserController { @Autowired UserService userService; /** * 从spring_boot_demo数据库中得到数据 * @return int */ public int getAgeOfUser(){ return userService.getAgeByUsername("springbootdemo"); } /** * 从other_data数据库中得到数据 * @return */ @DataSource(DataSourceName.SECOND) public int getAgeOfUser2(){ return userService.getAgeByUsername("springbootdemo"); } /** * 两个方法同时执行 * @return String */ @RequestMapping("/user/age") public String getAge(){ int age1=getAgeOfUser(); int age2=getAgeOfUser2(); return "spring_boot_demo:"+age1+";other_data:"+age2; } }

  得到的运行结果如下:

  

  很显然,切换数据源没有成功,加了切换注解的方法得到的显示结果还是主数据源的数据

二、问题思考:

  相比于之前使用单方法切换数据源成功的测试结果,这次的测试和之前的差别无非以下两点:

  1不使用注解(即默认数据源)的方法和使用注解(切换辅数据源)的方法同时被调用;   2、方法被嵌套在一个不使用注解的父方法中调用。

  那么针对以上两个情况再进行测试,去掉使用默认数据源的方法,只在父方法中嵌套一个进行调用:

  @RequestMapping("/user/age") public String getAge(){ int age2=getAgeOfUser2(); return "other_data:"+age2; }

  得到的结果如下所示:

  

  结果得到的还是主数据源的数据,也就是说,切换数据源的注解失效与另一个无注解的方法无关,而是因为被嵌套在一个无注解的父方法

  在无注解的父方法上加上切换数据源的注解,再次进行测试如下:

  @RequestMapping("/user/age")   @DataSource(DataSourceName.SECOND)   public String getAge(){     int age2=getAgeOfUser2();     return "other_data:"+age2;   }

  得到的结果是:

  

  到这儿,基本就清楚了。

  之所以切换数据源的注解失效,是因为方法嵌套时,子方法的DataSource注解被父方法覆盖了

三、问题解决

  1、使用代理对象:

  (1)引入spring-aspects依赖包:

<!-- spring-aspects --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.1.2.RELEASE</version> </dependency>

  (2)修改入口类的@EnableAspectJAutoProxy注解为:

@EnableAspectJAutoProxy(exposeProxy = true)

  exposeProxy = true的作用是暴露当前代理对象到当前线程绑定

  (3)修改controller层中方法的调用方式:

  AopContext.currentProxy()使用ThreadLocal保存了代理对象,所以直接把方法之间的调用方式改为代理对象之间的调用即可。

/** * 两个方法同时执行 * @return String */ @RequestMapping("/user/age") public String getAge(){ int age1=((UserController)AopContext.currentProxy()).getAgeOfUser(); int age2=((UserController)AopContext.currentProxy()).getAgeOfUser2(); return "spring_boot_demo:"+age1+";other_data:"+age2; }

  代码如上所示,使用((UserController)AopContext.currentProxy()).getAgeOfUser()的方式,通过代理对象调用方法,所得结果为:

  

  两个数据库的结果同时获取并显示了。

  2、把DataSource注解放到service层的方法中:

  (1)修改Service层的方法,加上注解:

@Override public int getAgeByUsername(String username) { return userMapper.getAgeByUsername(username); } @Override @DataSource(DataSourceName.SECOND) public int getAgeByUsername2(String username) { return userMapper.getAgeByUsername(username); }

  (2)在controller中直接调用即可:

  /** * 两个方法同时执行 * @return String */ @RequestMapping("/user/age") public String getAge(){ int age1=userService.getAgeByUsername("springbootdemo"); int age2=userService.getAgeByUsername2("springbootdemo"); return "spring_boot_demo:"+age1+";other_data:"+age2; }

  结果如下:

  

  


__EOF__

本文作者我命倾尘
本文链接https://www.cnblogs.com/guobin-/p/13710292.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   我命倾尘  阅读(2031)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
历史上的今天:
2019-09-22 Oracle数据库:PLSQL安装过程和SCOTT用户被锁的解决方法
点击右上角即可分享
微信分享提示