SpringBoot + Druid + Mybatis 配置多数据源(AOP方式)

1、配置文件  application-dev.yml 设置

spring:
  datasource:
    ds1:
      url: jdbc:mysql://10.126.89.86:58885/xxxx?useSSL=false
      username: xxxx
      password: xxxxx
      driver-class-name: com.mysql.jdbc.Driver
    ds2:
      url: jdbc:mysql://10.126.89.86:58885/xxx?useSSL=false
      username: xxxx
      password: xxxxxx
      driver-class-name: com.mysql.jdbc.Driver
mybatis:
  mapper-locations: classpath:mybatis/mapper/*.xml
  type-aliases-package: com.data.pcv.dao.model
  config-locations: classpath:mybatis/mybatis-config.xml
  configuration:
    map-underscore-to-camel-case: true
    use-generated-keys: true

2、配置Druid 多个数据源和 Druid监控Servlet

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import java.util.HashMap;
import java.util.Map;

@Configuration
public class DruidConfig {
 
    private static final Logger log = LoggerFactory.getLogger(DruidConfig.class);
 

 
    //数据源一
    @Bean(name = "ds1DataSource" )
    @ConfigurationProperties(prefix="spring.datasource.ds1")
    public DruidDataSource ds1DataSource() {
        DruidDataSource druidDataSource = new DruidDataSource();
        return druidDataSource;
    }
    //数据源二
    @Bean(name = "ds2DataSource" )
    @ConfigurationProperties(prefix="spring.datasource.ds2")
    public DruidDataSource ds2DataSource() {
        DruidDataSource druidDataSource = new DruidDataSource();

        return druidDataSource;
    }

    @Bean
    public ServletRegistrationBean druidServlet() {
        log.info("init Druid Servlet Configuration ");
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
        servletRegistrationBean.setServlet(new StatViewServlet());
        servletRegistrationBean.addUrlMappings("/druid/*");
        Map initParameters = new HashMap<>();
        initParameters.put("loginUsername", “admin");// 用户名
        initParameters.put("loginPassword", “admin");// 密码
        initParameters.put("allow","");
        initParameters.put("resetEnable", "false");// 禁用HTML页面上的“Reset All”功能
        //initParameters.put("allow", allowIp); // IP白名单 (没有配置或者为空,则允许所有访问)
        //initParameters.put("deny", "");// IP黑名单 (存在共同时,deny优先于allow)
        servletRegistrationBean.setInitParameters(initParameters);
        return servletRegistrationBean;
    }

 
    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new WebStatFilter());
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        return filterRegistrationBean;
    }
}

3、创建 动态数据源DynamicDataSource 类继承AbstractRoutingDataSource抽象类

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

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

public class DynamicDataSource extends AbstractRoutingDataSource {
    private static final ThreadLocal contextHolder = new ThreadLocal<>();

    /**
     * 配置DataSource, defaultTargetDataSource为主数据库
     */
    public DynamicDataSource(DataSource defaultTargetDataSource, Map targetDataSources) {
        super.setDefaultTargetDataSource(defaultTargetDataSource);
        super.setTargetDataSources(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();
    }

}

4、动态数据源配置注入,设置事务管理器和SQLSessionFactory

import com.alibaba.druid.pool.DruidDataSource;
import com.github.pagehelper.PageInterceptor;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
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.env.Environment;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

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

@Configuration
public class DynamicDataSourceConfig {

    //pagehelper 插件
    @Autowired
    private PageInterceptor pageInterceptor;
    
    //Spring环境上下文
    @Autowired
    private Environment environment;
    
    //注入mybatis 配置
    @Bean
    @ConfigurationProperties(prefix = "mybatis.configuration")
    public org.apache.ibatis.session.Configuration globalConfiguration() {
        return new org.apache.ibatis.session.Configuration();
    }
    
    //配置主数据源
    @Bean
    @Primary
    public DynamicDataSource dynamicDataSource( DruidDataSource ds1DataSource,
                                                DruidDataSource ds2DataSource) {
        Map targetDataSources = new HashMap<>(2);
        targetDataSources.put(Consts.DATASOURCE_PCV, ds1DataSource);
        targetDataSources.put(Consts.DATASOURCE_DAVINCI, ds2DataSource);
        // 还有数据源,在targetDataSources中继续添加
        System.out.println("DataSources:" + targetDataSources);
        return new DynamicDataSource(ds1DataSource, targetDataSources);
    }

    @Bean
    public DataSourceTransactionManager ds1TransactionManager(DynamicDataSource dynamicDataSource){
        return new DataSourceTransactionManager(dynamicDataSource);
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory( DynamicDataSource dynamicDataSource) throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dynamicDataSource);
        sqlSessionFactoryBean.setConfiguration(globalConfiguration());
        sqlSessionFactoryBean.setPlugins(new Interceptor[]{pageInterceptor});
        sqlSessionFactoryBean.setTypeAliasesPackage(environment.getProperty("mybatis.ds1.type-aliases-package"));
        sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(environment.getProperty("mybatis.ds1.mapper-locations")));
        return sqlSessionFactoryBean.getObject();
    }

}

5、自定义注解 并设置默认的数据源

import java.lang.annotation.*;

/**
 * 多数据源注解默认pcv
 */
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource {
    String value() default Consts.DATASOURCE_PCV;
}

6、切面

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.core.Ordered;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

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

    /**
     * 切点: 所有配置 DataSource 注解的方法
     */
    @Pointcut("@annotation(com.data.pcv.annotation.DataSource)")
    public void dataSourcePointCut() {}

    @Around("dataSourcePointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        DataSource ds = method.getAnnotation(DataSource.class);
        // 通过判断 DataSource 中的值来判断当前方法应用哪个数据源
        DynamicDataSource.setDataSource(ds.value());
        System.out.println("当前数据源: " + ds.value());
        logger.debug("set datasource is " + ds.value());
        try {
            return point.proceed();
        } finally {
            DynamicDataSource.clearDataSource();
            logger.debug("clean datasource");
        }
    }

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

7、启动类 排除 DataSource自动配置

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.Import;

@Import({DynamicDataSourceConfig.class})
@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
public class PCVApplication {

    public static void main(String[] args) {

        SpringApplication.run(PCVApplication.class, args);

    }

}

8、使用案例

普通方法使用默认的DataSource,若需要使用另一个DataSource,则在Service实现方法上加注解 @DataSource(指定的数据源)

@Service
public class DavinciUserServiceImp implements DavinciUserService {

    @Autowired
    DavinciUserModelMapper davinciUserModelMapper;

    @DataSource(Consts.DATASOURCE_DAVINCI)
    @Override
    public DavinciUserModel getByUserName(String username){

        return davinciUserModelMapper.selectByUserName(username);
    }

    @DataSource(Consts.DATASOURCE_DAVINCI)
    @Override
    public int insertSelective(DavinciUserModel insertModel) {

        return davinciUserModelMapper.insertSelective(insertModel);
    }

}

 

你可能感兴趣的:(Spring,Boot)