zoukankan      html  css  js  c++  java
  • Spring+Mybatis 多套数据源实现

    本文的特色

    • 使用Spring最小化配置,仅用经典的Spring Framework,并借用Spring Boot的ConfigurationProperties注解。
    • 最小化配置
    • 最小化依赖

    实现说明

    • 添加依赖,先添加Spring Framework必要依赖。
    • 添加Spring Boot 依赖,以使用ConfigurationProperties注解。【可选】
    • 实现AbstractRoutingDataSource,存储数据源
    • 定义三套数据源
    • 定义切面
    • 开启最小化必要注解
    • 启动入口定义

    添加依赖,先添加Spring Framework必要依赖

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-web</artifactId>
                <version>${org.springframework.version}</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>${org.springframework.version}</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>${org.springframework.version}</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context-support</artifactId>
                <version>${org.springframework.version}</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>${org.springframework.version}</version>
            </dependency>
    

    添加其他依赖

    Jackson

            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-core</artifactId>
                <version>${jackson.version}</version>
            </dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>${jackson.version}</version>
            </dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-annotations</artifactId>
                <version>${jackson.version}</version>
            </dependency>
    

    Mysql驱动

            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>
    

    Mybatis

            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>${mybatis.version}</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis-spring</artifactId>
                <version>${mybatis-spring.version}</version>
            </dependency>
    

    添加Spring Boot 依赖,以使用ConfigurationProperties注解。【可选】

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot</artifactId>
                <version>${spring-boot.version}</version>
            </dependency>
    
            <!-- ForConfigurationProperties -->
            <dependency>
                <groupId>javax.validation</groupId>
                <artifactId>validation-api</artifactId>
                <version>${validation-api.version}</version>
            </dependency>
            <dependency>
                <groupId>org.glassfish</groupId>
                <artifactId>javax.el</artifactId>
                <version>${javax.el.version}</version>
            </dependency>
            <dependency>
                <groupId>org.hibernate</groupId>
                <artifactId>hibernate-validator</artifactId>
                <version>5.3.6.Final</version>
            </dependency>
    

    依赖版本

    注意:spring-boot的版本和springframework是匹配的

    <jackson.version>2.9.4</jackson.version>
    <logback.version>1.2.3</logback.version>
    <logback.ext.version>0.1.4</logback.ext.version>
    <org.springframework.version>4.3.25.RELEASE</org.springframework.version>
    <spring-boot.version>1.5.22.RELEASE</spring-boot.version>
    <mybatis.version>3.3.1</mybatis.version>
    <mybatis-spring.version>1.2.3</mybatis-spring.version>
    <mysql.version>5.1.38</mysql.version>
    <javax.el.version>3.0.0</javax.el.version>
    <validation-api.version>1.1.0.Final</validation-api.version>
    

    实现AbstractRoutingDataSource,存储数据源

    DataSourceNames 枚举,用于指定数据源名称

    public enum DataSourceNames {
        ONE,
        TWO,
        SLANKKA;
    }
    
    

    DynamicDataSource

    public class DynamicDataSource extends AbstractRoutingDataSource {
        private static final ThreadLocal<DataSourceNames> dataSourceNameHolder = new ThreadLocal<>();
    
        public DynamicDataSource(
                DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
            super.setDefaultTargetDataSource(defaultTargetDataSource);
            super.setTargetDataSources(targetDataSources);
            super.afterPropertiesSet();
        }
    
        @Override
        protected Object determineCurrentLookupKey() {
            return getDataSource();
        }
    
        public static void setDataSource(DataSourceNames dataSource) {
            dataSourceNameHolder.set(dataSource);
        }
    
        public static DataSourceNames getDataSource() {
            return dataSourceNameHolder.get();
        }
    
        public static void clearDataSource() {
            dataSourceNameHolder.remove();
        }
    }
    
    

    定义SwitchSource注解,用于在方法上指定数据源

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface SwitchSource {
        DataSourceNames value() default DataSourceNames.ONE;
    }
    

    定义三套数据源

    数据源配置类 (Getter Setter省略)

    @ConfigurationProperties
    public class DatasourceConfig {
        private String url;
        private String driver;
        private String username;
        private String password;
    }
    
    
        @Bean("firstDataSource")
        public DataSource secondDataSource(@Qualifier("firstDatasourceConfig") @Autowired DatasourceConfig firstDatasourceConfig) {
            final DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
            driverManagerDataSource.setDriverClassName(firstDatasourceConfig.getDriver());
            driverManagerDataSource.setUrl(firstDatasourceConfig.getUrl());
            driverManagerDataSource.setUsername(firstDatasourceConfig.getUsername());
            driverManagerDataSource.setPassword(firstDatasourceConfig.getPassword());
            return driverManagerDataSource;
        }
    
    
        @Bean("secondDataSource")
        public DataSource secondDataSource(@Qualifier("secondDatasourceConfig") @Autowired DatasourceConfig secondDatasourceConfig) {
            final DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
            driverManagerDataSource.setDriverClassName(secondDatasourceConfig.getDriver());
            driverManagerDataSource.setUrl(secondDatasourceConfig.getUrl());
            driverManagerDataSource.setUsername(secondDatasourceConfig.getUsername());
            driverManagerDataSource.setPassword(secondDatasourceConfig.getPassword());
            return driverManagerDataSource;
        }
    
        @Bean("thirdDataSource")
        public DataSource thirdDataSource(@Qualifier("slankkaDatasourceConfig") @Autowired DatasourceConfig slankkaDatasourceConfig) {
            final DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
            driverManagerDataSource.setDriverClassName(slankkaDatasourceConfig.getDriver());
            driverManagerDataSource.setUrl(slankkaDatasourceConfig.getUrl());
            driverManagerDataSource.setUsername(slankkaDatasourceConfig.getUsername());
            driverManagerDataSource.setPassword(slankkaDatasourceConfig.getPassword());
            return driverManagerDataSource;
        }
    
        @Bean
        @DependsOn(value = {"firstDataSource", "secondDataSource", "thirdDataSource"})
        public DynamicDataSource dataSource(
                DataSource firstDataSource, DataSource secondDataSource, DataSource thirdDataSource) {
            Map<Object, Object> targetDataSources = new HashMap<>();
            targetDataSources.put(DataSourceNames.ONE, firstDataSource);
            targetDataSources.put(DataSourceNames.TWO, secondDataSource);
            targetDataSources.put(DataSourceNames.SLANKKA, thirdDataSource);
            return new DynamicDataSource(firstDataSource, targetDataSources);
        }
    

    数据源的配置

        @Bean
        @ConfigurationProperties
        public DatasourceConfig datasourceConfig() {
            return new DatasourceConfig();
        }
    
        @Bean
        @ConfigurationProperties("slankkatwo.datasource")
        public DatasourceConfig cloudDatasourceConfig() {
            return new DatasourceConfig();
        }
    
        @Bean
        @ConfigurationProperties("slankkathree.datasource")
        public DatasourceConfig platDatasourceConfig() {
            return new DatasourceConfig();
        }
    

    定义切面

    @Aspect
    @Component
    public class DataSourceAspect implements Ordered {
        protected Logger logger = LoggerFactory.getLogger(getClass());
    
        @Pointcut("@annotation(com.slankka.blog.route.SwitchSource)")
        public void dataSourcePointCut() {}
    
        @Around("dataSourcePointCut()")
        public Object around(ProceedingJoinPoint point) throws Throwable {
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
    
            SwitchSource ds = method.getAnnotation(SwitchSource.class);
            if (ds == null) {
                DynamicDataSource.setDataSource(DataSourceNames.ONE);
                logger.debug("set datasource <= " + DataSourceNames.ONE);
            } else {
                DynamicDataSource.setDataSource(ds.value());
                logger.debug("set datasource => " + ds.value());
            }
            try {
                return point.proceed();
            } finally {
                DynamicDataSource.clearDataSource();
                logger.debug("clean datasource");
            }
        }
    
        @Override
        public int getOrder() {
            return 1;
        }
    }
    

    Mybatis配置

        @Bean
        public SqlSessionFactoryBean sqlSessionFactory(@Autowired DataSource dataSource)
                throws IOException {
            final SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
            sqlSessionFactoryBean.setMapperLocations(
                    new PathMatchingResourcePatternResolver()
                            .getResources("classpath*:mybatis/**/*.xml"));
            sqlSessionFactoryBean.setConfigLocation(new ClassPathResource("mybatis-config.xml"));
            sqlSessionFactoryBean.setDataSource(dataSource);
            return sqlSessionFactoryBean;
        }
    
        @Bean
        //可选
        public JdbcTemplate jdbcTemplate(@Autowired DataSource dataSource) throws IOException {
            return new JdbcTemplate(dataSource);
        }
    
        @Bean
        public DataSourceTransactionManager transactionManager(@Autowired DataSource dataSource) {
            return new DataSourceTransactionManager(dataSource);
        }
    
        @Bean
        public MapperScannerConfigurer mapperScannerConfigurer() {
            final MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
            mapperScannerConfigurer.setBasePackage("com.slankka.blog.dao");
            mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
            return mapperScannerConfigurer;
        }
    

    开启最小化必要注解

    @Configuration
    @EnableConfigurationProperties(DatasourceConfig.class)
    @EnableAspectJAutoProxy(proxyTargetClass = true)
    public class AnnotationDrivenAppConfig {
        //配置类
    }
    
    

    启动入口定义

    说明:这里手动启动Spring Framework,没有用到SpringBoot的方式

    public class Application {
    
        public static void main(String[] args) {
            post();
        }
    
        public static void post() {
            ConfigurableApplicationContext ctx =
                    new AnnotationConfigApplicationContext("com.slankka.blog");
            ctx.start();
            try{
                //business
            }finally {
                ctx.close();
            }
        }
    }
    
  • 相关阅读:
    寻找回文数
    【C/C++语言入门篇】 位运算
    怎样判断输入是否结束
    命名那个数字
    Broken Necklace
    C#打造邮件接受器VS2005版
    C#应用程序打包时自动安装MSDE
    SQL6.5到2005发布的版本号搜集整理
    SQL无限分类存储过程整理2
    ASP.NET调用SWF代码文件
  • 原文地址:https://www.cnblogs.com/slankka/p/14785440.html
Copyright © 2011-2022 走看看