springBoot配置多数据源

通过在mapper接口上添加自定数据源注解@DataSource来制定数据源

1.添加切面aspectjweaver依赖

            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.9.7</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-aop</artifactId>
                <version>1.5.9.RELEASE</version>
            </dependency>

2.启动类添加切面支持注解@EnableAspectJAutoProxy(proxyTargetClass = true)

@Import({DynamicDataSourceConfig.class})

exclude = {DataSourceAutoConfiguration.class} 不加这个会报错,循环依赖问题(查了好久才解决)

import org.linlinjava.litemall.db.datasources.DynamicDataSourceConfig;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Import;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@MapperScan("org.linlinjava.litemall.db.dao")
@EnableTransactionManagement
@EnableAspectJAutoProxy(proxyTargetClass = true)
@EnableScheduling
@Import({DynamicDataSourceConfig.class})
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

3自定义注解DataSource.java


import java.lang.annotation.*;

/**
 * 多数据源注解
 *
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
    String name() default "";
}

数据源名称枚举

/**
 * 增加多数据源,在此配置
 *
 */
public interface DataSourceNames {
    String LITEMALL = "mall";

    String ZOOM = "zoom";

}

动态数据源配置类


import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * 动态数据源
 *
 */
public class DynamicDataSource extends AbstractRoutingDataSource {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    public DynamicDataSource(DataSource defaultTargetDataSource, Map<String, DataSource> targetDataSources) {
        super.setDefaultTargetDataSource(defaultTargetDataSource);
        super.setTargetDataSources(new HashMap<>(targetDataSources));
        super.afterPropertiesSet();
    }

    @Override
    protected Object determineCurrentLookupKey() {
        return getDataSource();
    }

    public static void setDataSource(String dataSource) {
        contextHolder.set(dataSource);
    }

    public static String getDataSource() {
        return contextHolder.get();
    }

    public static void clearDataSource() {
        contextHolder.remove();
    }

}

配置多数据源


import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.core.Ordered;
import org.springframework.stereotype.Component;


import javax.sql.DataSource;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 配置多数据源
 *
 */
@Configuration
public class DynamicDataSourceConfig {

    @Bean
    @ConfigurationProperties("spring.datasource.druid.mall")
    public DataSource liteMallDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties("spring.datasource.druid.zoom")
    public DataSource zoomDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @Primary
    public DynamicDataSource dataSource(DataSource liteMallDataSource, DataSource zoomDataSource) {
        Map<String, DataSource> targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceNames.LITEMALL, liteMallDataSource);
        targetDataSources.put(DataSourceNames.ZOOM, zoomDataSource);
        return new DynamicDataSource(liteMallDataSource, targetDataSources);
    }

    @Aspect
    @Component
    class DataSourceAspect implements Ordered {
        protected Logger logger = LoggerFactory.getLogger(getClass());

        public DataSourceAspect() {
            System.out.println(0);
        }

        @Pointcut("@within(org.linlinjava.litemall.db.datasources.annotation.DataSource)")
        public void dataSourcePointCut() {
            System.out.println(0);
        }

        @Around("dataSourcePointCut()")
        public Object around(ProceedingJoinPoint point) throws Throwable {

            org.linlinjava.litemall.db.datasources.annotation.DataSource ds = null;

            Class clazz = point.getTarget().getClass();
            ds = (org.linlinjava.litemall.db.datasources.annotation.DataSource) clazz.getAnnotation(org.linlinjava.litemall.db.datasources.annotation.DataSource.class);

            if (ds == null) {
                MethodSignature signature = (MethodSignature) point.getSignature();
                Method method = signature.getMethod();
                ds = method.getAnnotation(org.linlinjava.litemall.db.datasources.annotation.DataSource.class);
            }

            if (ds == null) {
                DynamicDataSource.setDataSource(DataSourceNames.LITEMALL);
                logger.debug("set datasource is " + DataSourceNames.LITEMALL);
            } else {
                DynamicDataSource.setDataSource(ds.name());
                logger.debug("set datasource is " + ds.name());
            }

            try {
                return point.proceed();
            } finally {
                DynamicDataSource.clearDataSource();
                logger.debug("clean datasource");
            }
        }

        @Override
        public int getOrder() {
            return 1;
        }
    }

}

4.Yaml配置

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      zoom:  #数据源2
        url: xxxxxx/zoom?useUnicode=true&characterEncoding=utf8&useSSL=false
        driver-class-name:  com.mysql.cj.jdbc.Driver
        username: 0000
        password: 00000
        filter:
          slf4j:
            enabled: true
      mall:
        url:  jdbc:xxxxxx/litemall?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&verifyServerCertificate=false&useSSL=false
        driver-class-name:  com.mysql.cj.jdbc.Driver
        username:  00000
        password:  00000
        initial-size:  10
        max-active:  50
        min-idle:  10
        max-wait:  60000
        pool-prepared-statements:  true
        max-pool-prepared-statement-per-connection-size:  20
        validation-query:  SELECT 1 FROM DUAL
        test-on-borrow:  false
        test-on-return:  false
        test-while-idle:  true
        time-between-eviction-runs-millis:  60000
        webStatFilter:
          enabled: true
        statViewServlet:
          enabled: false
        filter:
          stat:
            enabled: false

5.测试


import org.junit.Test;
import org.junit.runner.RunWith;
import org.linlinjava.litemall.db.dao.StatMapper;
import org.linlinjava.litemall.db.dao.ZoomMapper;
import org.linlinjava.litemall.db.datasources.DynamicDataSourceConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;

import javax.annotation.Resource;

@WebAppConfiguration
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
@RunWith(SpringRunner.class)
@SpringBootTest
@Import({DynamicDataSourceConfig.class})
public class DbTest {

    @Autowired
    private ZoomMapper zoomMapper;

    @Test
    public void test() {
        System.out.println(zoomMapper.queryName());
    }

}

6,可能出现的异常

***************************
APPLICATION FAILED TO START
***************************

Description:

The dependencies of some of the beans in the application context form a cycle:

zoomMapperService (field org.linlinjava.litemall.db.dao.ZoomMapper org.linlinjava.litemall.db.dao.impl.ZoomMapperService.zoomMapper)

zoomMapper defined in file [F:\workcode\litemall\litemall-db\target\classes\org\linlinjava\litemall\db\dao\ZoomMapper.class]

sqlSessionFactory defined in class path resource [org/mybatis/spring/boot/autoconfigure/MybatisAutoConfiguration.class]
┌─────┐
| dataSource defined in class path resource [org/linlinjava/litemall/db/datasources/DynamicDataSourceConfig.class]
↑ ↓
| firstDataSource defined in class path resource [org/linlinjava/litemall/db/datasources/DynamicDataSourceConfig.class]
↑ ↓
| org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerInvoker

循环依赖问题

2yaml配置问题

Caused by: org.yaml.snakeyaml.parser.ParserException: while parsing a block mapping
 in 'reader', line 9, column 5:
        type: com.alibaba.druid.pool.Dru ... 
        ^
expected <block end>, but found '<block mapping start>'
 in 'reader', line 19, column 7:
          mall:
          ^

    at org.yaml.snakeyaml.parser.ParserImpl$ParseBlockMappingKey.produce(ParserImpl.java:572)
    at org.yaml.snakeyaml.parser.ParserImpl.peekEvent(ParserImpl.java:158)
    at org.yaml.snakeyaml.parser.ParserImpl.checkEvent(ParserImpl.java:148)
    at org.yaml.snakeyaml.composer.Composer.composeMappingNode(Composer.java:214)
    at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:144)
    at org.yaml.snakeyaml.composer.Composer.composeValueNode(Composer.java:236)
    at org.yaml.snakeyaml.composer.Composer.composeMappingChildren(Composer.java:227)
    at org.yaml.snakeyaml.composer.Composer.composeMappingNode(Composer.java:215)
    at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:144)
    at org.yaml.snakeyaml.composer.Composer.composeValueNode(Composer.java:236)
    at org.yaml.snakeyaml.composer.Composer.composeMappingChildren(Composer.java:227)
    at org.yaml.snakeyaml.composer.Composer.composeMappingNode(Composer.java:215)
    at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:144)
    at org.yaml.snakeyaml.composer.Composer.getNode(Composer.java:85)
    at org.yaml.snakeyaml.constructor.BaseConstructor.getData(BaseConstructor.java:123)
    at org.yaml.snakeyaml.Yaml$1.next(Yaml.java:547)
    at org.springframework.beans.factory.config.YamlProcessor.process(YamlProcessor.java:160)
    at org.springframework.beans.factory.config.YamlProcessor.process(YamlProcessor.java:134)
    at org.springframework.boot.env.OriginTrackedYamlLoader.load(OriginTrackedYamlLoader.java:75)
    at org.springframework.boot.env.YamlPropertySourceLoader.load(YamlPropertySourceLoader.java:50)
    at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.loadDocuments(ConfigFileApplicationListener.java:574)
    at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.load(ConfigFileApplicationListener.java:528)
    ... 48 common frames omitted

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值