springboot+mybatis配置多数据源并利用aop实现自动切换

硅谷探秘者 560 0 0

springboot+mybatis配置多数据源并利用aop实现自动切换

1.项目大致结构

2.pom依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <scope>runtime</scope>
      </dependency>
      <dependency>
          <groupId>org.mybatis.spring.boot</groupId>
          <artifactId>mybatis-spring-boot-starter</artifactId>
          <version>2.0.1</version>
      </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
       
       <!--aop依赖 项目中使用了aop,实现数据源的自动切换-->
  	   <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
        </dependency>

3.yml配置文件

server:
  port: 8087
  servlet:
        context-path: / #项目路径
 
spring: 
  datasource: 
    main: 
      username: root
      password: jiajia123
      url: jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
      driver-class-name: com.mysql.jdbc.Driver
    secondary: 
      username: root
      password: jiajia123
      url: jdbc:mysql://localhost:3306/db2?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
      driver-class-name: com.mysql.jdbc.Driver
    
mybatis:
  mapper-locations: classpath:com/oauth/server/mapper/*Mapper.xml
  type-aliases-package: com.oauth.server.entity
  configuration:      
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #sql日志打印
        call-setters-on-nulls: true #解决返回类型为Map的时候如果值为null将不会封装此字段

在启动类中修改@SpringBootApplication这个配置为:

@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})

意思要去掉springboot默认的数据源配置,使用自己定义的数据源配置。

4.DS注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * 
 * @author 硅谷探秘者(jia)
 *
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DS {
    String value() default "main";
}

        这个注解是用在service层方法上的,从配置文件中可以看出,配置了两个数据源,主数据源main和辅数据源secondary,如果service方法想访问main这个数据源,则不需要任何配置它默认会访问main数据源,或在方法上加个@DS("main")注解,如果想访问辅数据源secondary则需要在方法上加上@DS("secondary")注解。

例子:

	//访问主数据源
    public void test() {
		// TODO Auto-generated method stub
		testMapper.test();
	}
    //访问辅数据源
	@DS("secondary")
	public void test2() {
		// TODO Auto-generated method stub
		testMapperDb2.test();
	}

        注意这个注解一定是要在运行是可以访问到的,所以要加上@Retention(RetentionPolicy.RUNTIME)这个元注解。

5.数据源配置

/**
 * @author 硅谷探秘者(jia)
 */
public class DataSourceContextHolder {
    /**
     * 默认数据源
     */
    public static final String DEFAULT_DS = "main";
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
    // 设置数据源名
    public static void setDB(String dbType) {
        contextHolder.set(dbType);
    }
    // 获取数据源名
    public static String getDB() {
        return (contextHolder.get());
    }
    // 清除数据源名
    public static void clearDB() {
        contextHolder.remove();
    }
}
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**
 * @author 硅谷探秘者(jia)
 */
public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDB();
    }
}
主要配置
package com.oauth.server.conf;

import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
 * @author 硅谷探秘者(jia)
 */
@Configuration
public class DataSourceConfig {

	/**
	 * 	主数据源配置
	 * @return
	 */
    @Bean(name = "main")
    @ConfigurationProperties(prefix = "spring.datasource.main")
    public DataSource main() {
        return DataSourceBuilder.create().build();
    }

    /**
     * 	辅数据源配置
     * @return
     */
    @Bean(name = "secondary")
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource secondary() {
        return DataSourceBuilder.create().build();
    }

    /**
     * 动态数据源: 通过AOP在不同数据源之间动态切换
     *
     * @return
     */
    @Primary
    @Bean(name = "dynamicDS1")
    public DataSource dataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        // 默认数据源
        dynamicDataSource.setDefaultTargetDataSource(main());

        // 配置多数据源
        Map<Object, Object> dsMap = new HashMap<Object, Object>(5);
        dsMap.put("main", main());
        dsMap.put("secondary", secondary());

        dynamicDataSource.setTargetDataSources(dsMap);
        return dynamicDataSource;
    }
    /**
     * 配置@Transactional注解事物
     * @return
     */
    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource());
    }
}
aop配置,拦截带@DS注解的方法
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
 * @author 硅谷探秘者(jia)
 */
@Aspect
@Component
public class DynamicDataSourceAspect {

    @Before("@annotation(DS)")
    public void beforeSwitchDS(JoinPoint point){
    	
        //获得当前访问的class
        Class<?> className = point.getTarget().getClass();

        //获得访问的方法名
        String methodName = point.getSignature().getName();
        //得到方法的参数的类型
        Class<?>[] argClass = ((MethodSignature)point.getSignature()).getParameterTypes();
        String dataSource = DataSourceContextHolder.DEFAULT_DS;
        try {
            // 得到访问的方法对象
            Method method = className.getMethod(methodName, argClass);
            System.out.println(method.getName());
            System.out.println(method.isAnnotationPresent(DS.class));
            // 判断是否存在@DS注解
            if (method.isAnnotationPresent(DS.class)) {
                DS annotation = method.getAnnotation(DS.class);
                // 取出注解中的数据源名
                dataSource = annotation.value();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(dataSource);
        // 切换数据源
        DataSourceContextHolder.setDB(dataSource);
    }

    @After("@annotation(DS)")
    public void afterSwitchDS(JoinPoint point){
        DataSourceContextHolder.clearDB();
    }
}

这样配置基本完成,使用的时候只需要在方法上添加@DS注解,标明你要访问的数据源即可。

server层例子

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.oauth.server.conf.DS;
import com.oauth.server.mapper.TestMapper;
import com.oauth.server.mapper.TestMapperDb2;
@Service
public class TestService {
	@Autowired
	private TestMapper testMapper;
	@Autowired
	private TestMapperDb2 testMapperDb2;
	public void test() {
		// TODO Auto-generated method stub
		testMapper.test();
	}
	@DS("secondary")
	public void test2() {
		// TODO Auto-generated method stub
		testMapperDb2.test();
	}
}

 

猜你喜欢
java项目 519 springboot+mybatisaop(demo)
框架 2536 spring:datasource:main:#主username:rootpassword:123456jdbc-url:jdbc:mysql://localhost:3306/main?useUni
linux系统 2858 方案一:一般如果以html,htm,gif,jpg,jpeg,bmp,png,ico,txt,js,css结尾的资,均由nginx处理,否则转发到相应的服务即可server{listen80
spring/springmvc 4778 springmvc启时从库中初始化系统常量设计的目标是,把项目的系统常量,放在库中,在项目初始化时从项目中获取信息,反射技术,把key-value对应的值封装进类。1
java 数据库 1063 java项目-库之间定时进行服务(右上方下载)压缩包内附sql脚本,本项目为springboot+mybatis框架,导入项目即可启测试。目的,两个库定时进行同步,定时
weblog 1426 vue使v-model(双向绑定)收集表单!DOCTYPEhtmlhtml head metacharset="UTF-8" title/title scriptsrc="js
框架 502 呢?首先我们有一个基础的类BasePage,这个类里面只有page,limit,index这三个属性,我们在创建其他查询参封装类的时候要继承BasePage这个类。然后我们的参解析
框架 402 maven打包态替文件的值pom文件添加profilesprofileiddev/idpropertiesprofileActivedev/profileActive
归档
2018年11月  12 2018年12月  33 2019年01月  28 2019年02月  28 2019年03月  32 2019年04月  27 2019年05月  33 2019年06月  6 2019年07月  12 2019年08月  12 2019年09月  21 2019年10月  8 2019年11月  15 2019年12月  25 2020年01月  9 2020年02月  5 2020年03月  16 2020年04月  4 2020年06月  1 2020年07月  7 2020年08月  13 2020年09月  9 2020年10月  5 2020年12月  3 2021年01月  1 2021年02月  5 2021年03月  7
标签
算法基础 linux 前端 c++ 数据结构 框架 数据库 计算机基础 储备知识 java基础 ASM 其他 深入理解java虚拟机 nginx git 消息中间件 搜索 maven redis docker dubbo
目录