一、问题如下:

  使用的是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. RocketMQ在windows环境下的安装(转)

    原博地址:https://www.jianshu.com/p/4a275e779afa 一.预备环境 1.系统 Windows 2. 环境 JDK1.8.Maven.Git 二. RocketMQ部署 ...

  2. echars 饼图使用

    option = {       tooltip: {         trigger: 'item',         formatter: '{a} <br/>{b}: {c} ({d ...

  3. 风变编程-Python基础语法

    第0关-千寻的名字 目录 1.范例1 2.范例2 1.知识点总结 2.范例 1)单引号和双引号 2)三引号 3)转义字符 1.知识点总结 1)变量 2)变量名 3)变量的命名规范 4)等于与赋值的区别 ...

  4. 1、Entity Framework Core 3.1入门教程-概述和准备工作

    本文章是根据 微软MVP solenovex(杨旭)老师的视频教程编写而来,再加上自己的一些理解. 视频教程地址:https://www.bilibili.com/video/BV1xa4y1v7rR ...

  5. poi解析Excel内容

    poi可以将指定目录下的Excel中的内容解析.读取到java程序中.下面是一个Demo: 使用poi需要导下包,如下: 首先是准备读取的Excel表,存放在"E:\programming\ ...

  6. 焦大:SEO重思录(上)收录量和收录率的重新定位

    http://www.wocaoseo.com/thread-198-1-1.html 前一段焦大在seo前线就看到有人问为何我收录量很大但是流量很低呢?有时候几百万的收录量但是流量却只有1000不到 ...

  7. CSAPP bomb分析

    CSAPP bomb分析 问题介绍 这是一个关于反汇编方面的问题,根据已有的二进制代码来推测程序中的特定条件,主要参考了以下各个博客: CSDN 1 CSDN 2 CSDN 3 CSDN 4 stac ...

  8. 从后端到前端之Vue(六)表单组件

    表单组件 做项目的时候会遇到一个比较头疼的问题,一个大表单里面有好多控件,一个一个做设置太麻烦,更头疼的是,需求还总在变化,一会多选.一会单选.一会下拉的,变来变去的烦死宝宝了. 那么怎么解决这个问题 ...

  9. 非旋Treap——fhq treap

    https://www.luogu.org/problemnew/show/P3369 知识点:1.拆分split,合并merge 2.split,merge要点:通过传址调用来简便代码 3.记得ro ...

  10. [bash]查找指定目录下符合格式的txt文件

    需求: 查找指定目录下符合yyyy-MM-dd(-b)NNN.txt格式的文件,如“2020-03-22-b888.txt” 目标目录内容: [root@localhost bashs]# ll /r ...