SpringBoot框架:两个方法同时调用时父方法使内部方法的DataSource注解失效的解决办法
一、问题如下:
使用的是SpringBoot框架:通过AOP和自定义注解完成druid连接池的动态数据源切换(三)中的两个数据库spring_boot_demo和other_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;
}
结果如下:

SpringBoot框架:两个方法同时调用时父方法使内部方法的DataSource注解失效的解决办法的更多相关文章
- springboot 使用maven 打包 报 (请使用 -source 7 或更高版本以启用 diamond 运算符) 错误解决办法
在使用springboot maven 打包时 报如下错误 (请使用 -source 7 或更高版本以启用 diamond 运算符) pom.xml编译插件 配置如下: <plugin> ...
- web自动化selenium click()方法失效的解决办法
使用Python写web-ui自动化脚本时,如果浏览器窗口比较小或者电脑屏幕比较小时, 可能会遇到页面元素的点击click()方法失效的问题,报错如下: Element <span>... ...
- 第二十六篇、因为自定item(nav)而使系统右滑返回手势失效的解决方法
@interface ViewController () <uigesturerecognizerdelegate> @end@implementation ViewController ...
- SpringBoot 内部方法调用,事务不起作用的原因及解决办法
在做业务开发时,遇到了一个事务不起作用的问题.大概流程是这样的,方法内部的定时任务调用了一个带事务的方法,失败后事务没有回滚.查阅资料后,问题得到解决,记录下来分享给大家. 场景 我在这里模拟一个场景 ...
- vue 父子组件传值以及方法调用,平行组件之间传值以及方法调用大全
vue项目经常需要组件间的传值以及方法调用,具体场景就不说了,都知道.基本上所有的传值都可以用vuex状态管理来实现,只要在组件内监听vuex就好. vue常用的传值方式以及方法有: 1. 父值传子( ...
- python类的内部方法
目录 一.绑定方法与非绑定方法 1.绑定方法 2.非绑定方法 二.property 1.什么是property? 2.为什么要用property? 3.如何使用property? 三.isinstan ...
- SpringBoot在Impl类中调用其它service层失败解决办法
在AImpl.java文件中引用BImpl.java的方法,编译正常,运行到调用的地方,报空指针异常,跟踪到异常位置,发现service为空,也就是按照之前controller层通过@Autowire ...
- Spring 内部方法调用失效问题(AOP)
AOP使用的是动态代理的机制,它会给类生成一个代理类,事务的相关操作都在代理类上完成.内部方式使用this调用方式时,使用的是实例调用,并没有通过代理类调用方法,所以会导致事务失效. 解决办法 方式一 ...
- SpringBoot框架——从SpringBoot看IoC容器初始化流程之方法分析
目录 一.概观Spring Boot 二.Spring Boot应用初始化 2.1 初始化入口 2.2 SpringApplication的run方法 2.3 方法分析 三.容器创建与初始化 3.1 ...
随机推荐
- RocketMQ在windows环境下的安装(转)
原博地址:https://www.jianshu.com/p/4a275e779afa 一.预备环境 1.系统 Windows 2. 环境 JDK1.8.Maven.Git 二. RocketMQ部署 ...
- echars 饼图使用
option = { tooltip: { trigger: 'item', formatter: '{a} <br/>{b}: {c} ({d ...
- 风变编程-Python基础语法
第0关-千寻的名字 目录 1.范例1 2.范例2 1.知识点总结 2.范例 1)单引号和双引号 2)三引号 3)转义字符 1.知识点总结 1)变量 2)变量名 3)变量的命名规范 4)等于与赋值的区别 ...
- 1、Entity Framework Core 3.1入门教程-概述和准备工作
本文章是根据 微软MVP solenovex(杨旭)老师的视频教程编写而来,再加上自己的一些理解. 视频教程地址:https://www.bilibili.com/video/BV1xa4y1v7rR ...
- poi解析Excel内容
poi可以将指定目录下的Excel中的内容解析.读取到java程序中.下面是一个Demo: 使用poi需要导下包,如下: 首先是准备读取的Excel表,存放在"E:\programming\ ...
- 焦大:SEO重思录(上)收录量和收录率的重新定位
http://www.wocaoseo.com/thread-198-1-1.html 前一段焦大在seo前线就看到有人问为何我收录量很大但是流量很低呢?有时候几百万的收录量但是流量却只有1000不到 ...
- CSAPP bomb分析
CSAPP bomb分析 问题介绍 这是一个关于反汇编方面的问题,根据已有的二进制代码来推测程序中的特定条件,主要参考了以下各个博客: CSDN 1 CSDN 2 CSDN 3 CSDN 4 stac ...
- 从后端到前端之Vue(六)表单组件
表单组件 做项目的时候会遇到一个比较头疼的问题,一个大表单里面有好多控件,一个一个做设置太麻烦,更头疼的是,需求还总在变化,一会多选.一会单选.一会下拉的,变来变去的烦死宝宝了. 那么怎么解决这个问题 ...
- 非旋Treap——fhq treap
https://www.luogu.org/problemnew/show/P3369 知识点:1.拆分split,合并merge 2.split,merge要点:通过传址调用来简便代码 3.记得ro ...
- [bash]查找指定目录下符合格式的txt文件
需求: 查找指定目录下符合yyyy-MM-dd(-b)NNN.txt格式的文件,如“2020-03-22-b888.txt” 目标目录内容: [root@localhost bashs]# ll /r ...