一、问题如下:

  使用的是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;
}

  结果如下:

  

  

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

  1. springboot 使用maven 打包 报 (请使用 -source 7 或更高版本以启用 diamond 运算符) 错误解决办法

    在使用springboot maven 打包时 报如下错误 (请使用 -source 7 或更高版本以启用 diamond 运算符) pom.xml编译插件 配置如下: <plugin> ...

  2. web自动化selenium click()方法失效的解决办法

    使用Python写web-ui自动化脚本时,如果浏览器窗口比较小或者电脑屏幕比较小时, 可能会遇到页面元素的点击click()方法失效的问题,报错如下: Element <span>... ...

  3. 第二十六篇、因为自定item(nav)而使系统右滑返回手势失效的解决方法

    @interface ViewController () <uigesturerecognizerdelegate> @end@implementation ViewController ...

  4. SpringBoot 内部方法调用,事务不起作用的原因及解决办法

    在做业务开发时,遇到了一个事务不起作用的问题.大概流程是这样的,方法内部的定时任务调用了一个带事务的方法,失败后事务没有回滚.查阅资料后,问题得到解决,记录下来分享给大家. 场景 我在这里模拟一个场景 ...

  5. vue 父子组件传值以及方法调用,平行组件之间传值以及方法调用大全

    vue项目经常需要组件间的传值以及方法调用,具体场景就不说了,都知道.基本上所有的传值都可以用vuex状态管理来实现,只要在组件内监听vuex就好. vue常用的传值方式以及方法有: 1. 父值传子( ...

  6. python类的内部方法

    目录 一.绑定方法与非绑定方法 1.绑定方法 2.非绑定方法 二.property 1.什么是property? 2.为什么要用property? 3.如何使用property? 三.isinstan ...

  7. SpringBoot在Impl类中调用其它service层失败解决办法

    在AImpl.java文件中引用BImpl.java的方法,编译正常,运行到调用的地方,报空指针异常,跟踪到异常位置,发现service为空,也就是按照之前controller层通过@Autowire ...

  8. Spring 内部方法调用失效问题(AOP)

    AOP使用的是动态代理的机制,它会给类生成一个代理类,事务的相关操作都在代理类上完成.内部方式使用this调用方式时,使用的是实例调用,并没有通过代理类调用方法,所以会导致事务失效. 解决办法 方式一 ...

  9. SpringBoot框架——从SpringBoot看IoC容器初始化流程之方法分析

    目录 一.概观Spring Boot 二.Spring Boot应用初始化 2.1 初始化入口 2.2 SpringApplication的run方法 2.3 方法分析 三.容器创建与初始化 3.1 ...

随机推荐

  1. VUE 中引入百度地图(vue-Baidu-Map)

    1.安装 $ npm install vue-baidu-map --save 2.全局注册,在main.js中引入以下代码 import BaiduMap from 'vue-baidu-map' ...

  2. python 计算文件md5值

    md5是一种常见不可逆加密算法,使用简单,计算速度快,在很多场景下都会用到,比如:给用户上传的文件命名,数据库中保存的用户密码,下载文件后检验文件是否正确等.下面讲解在python中如何使用md5算法 ...

  3. Java数据结构——二叉树节点的增删改查、获取深度及最大最小值

    一.查找最大值 // 查找最大值 public static Node maxNode() { Node node = root; Node maxNode = node; while (node ! ...

  4. 洛谷p1052过河 路径压缩+dp

    洛谷 P1052 过河 思路部分可以看这篇博客 我将在这里对其进行一些解释与补充 首先我们先看题 乍一看 这不是模板题吗 然后开开心心的敲了一个简单dp上去 #include<iostream& ...

  5. Java 接口简述

    Java 接口 接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明.一个类通过继承接口的方式,从而来继承接口的抽象方法. 接口并 ...

  6. 网站seo整站优化有什么优势

    http://www.wocaoseo.com/thread-314-1-1.html       现在很多企业找网络公司做网站优化,已经不再像以前那样做目标关键词,而是通过整站优化来达到企业营销目的 ...

  7. e3mall商城的归纳总结7之solr搭建和应用

    敬给读者的话 本文主要应用的技术是solr技术的搭建和应用,本文小编尽量写的更详细一些,让读者在不考虑项目的情况下也能正常完成solr的搭建,说完搭建之后,再说明运行solrj在项目中如何应用solr ...

  8. 在Spring中拦截器的使用

    Filter Filter是Servlet容器实现的,并不是由Spring 实现的 下面是一个例子 import java.io.IOException; import javax.servlet.F ...

  9. 如何设置Tomact的标题,运行Tomcat显示为自己程序的命名

    当我们使用Tomcat部署好一个web系统后,在窗口处默认会显示Tomcat名字.但如果我们用多个Tomcat部署时,则需要区分这些窗口,这是需要修改Tomact的配置,来设置一个我们需要显示的标题. ...

  10. Diophantus of Alexandria(唯一分解定理)

    Diophantus of Alexandria was an Egypt mathematician living in Alexandria. He was one of the first ma ...