1、写对应枚举的数据源
public enum DataSourceEnum {
DB1("空铁", "datasource1"),
DB2("同程", "datasource2"),
DB3("账号", "datasource3");
private String name;
private String value;
DataSourceEnum(String name, String value) {
this.name = name;
this.value = value;
}
public String getName(){
return this.name;
}
public String getValue() {
return this.value;
}
}
2、实现注解功能
可以使用注解的方式,注解sql使用哪个数据源,在执行sql的时候,就会自动选择对应的数据源
import java.lang.annotation.*;
@Target({ElementType.METHOD,ElementType.TYPE}) //固定写法
@Retention(RetentionPolicy.RUNTIME) //固定写法
@Documented //固定写法
public @interface DataSource //可自定义注解名字
{
DataSourceEnum value() default DataSourceEnum.DB1; //默认的数据源,此处的数据源是自己写的配置
}
3、切面,实现注解形式自动切换数据源
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Aspect
@Component
@Slf4j
@Order(-1)
public class DataSourceAspect {
//↓↓↓此处的DataSource路径是注解的路径,通过注解实现切面功能
@Pointcut("@within(com.ccservice.searchordernum.config.DataSource)||@annotation(com.ccservice.searchordernum.config.DataSource)")
public void pointCut(){}
//↓↓↓annotation中的datasource是下面方法中的参数。参数中的datasource是注解类
@Before("pointCut() && @annotation(dataSource)")
public void doBefor(DataSource dataSource){
log.info("选择数据源:{}", dataSource.value().getName()); //此处加一个日志,打印出来切换的数据源
//此处设置切换数据源。动态切换。后续我们设置数据源的时候以枚举的value作为key,所以此处设置value就达到了切换数据源的效果
DataSourceContextHolder.setDatasource(dataSource.value().getValue());
}
@After("pointCut()")
public void doAfter() {
DataSourceContextHolder.clear(); //之后进行数据源清空
}
}
4、配置druid监控页面
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
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;
@Configuration
public class DataSourceConfiguration {
@Bean
public ServletRegistrationBean startViewServlet(){
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
// IP白名单 此处最好把黑白名单去掉,暂时不清楚怎么弄的
servletRegistrationBean.addInitParameter("allow","127.0.0.1");
// IP黑名单(共同存在时,deny优先于allow)
servletRegistrationBean.addInitParameter("deny","127.0.0.1");
//控制台管理用户 配置账号密码等
servletRegistrationBean.addInitParameter("loginUsername","admin");
servletRegistrationBean.addInitParameter("loginPassword","123456");
//是否能够重置数据
servletRegistrationBean.addInitParameter("resetEnable","false");
return servletRegistrationBean;
}
@Bean
public FilterRegistrationBean statFilter(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
//添加过滤规则
filterRegistrationBean.addUrlPatterns("/*");
//忽略过滤的格式
filterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
return filterRegistrationBean;
}
}
5、数据源配置功能类
//该类用于配置数据源。设置好既有数据源后,后续可以进行配置使用哪个。配合切面,可以达到动态切换的功能
public class DataSourceContextHolder {
private static final ThreadLocal<String> contextHolder =new InheritableThreadLocal<>();
public static void setDatasource(String db) {
contextHolder.set(db);
}
public static String getDatasource(){
return contextHolder.get();
}
public static void clear(){
contextHolder.remove();
}
}
6、多数据源关联类
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
//将多个数据源关联起来
public class MultipleDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDatasource();
}
}
7、数据源、数据库等设置类
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.mybatis.spring.annotation.MapperScan;
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.context.annotation.Profile;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
* <p>
* MybatisPlus配置
* </p>
* @author geekidea
* @since 2018-11-08
*/
@Configuration
@MapperScan({"com.ccservice.**.mapper"})
@Slf4j
public class MyBatisPlusConfig {
/**
* mybatis-plus分页插件<br> 固定,不需要修改
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
/**
* SQL执行效率插件 固定,不需要修改
*/
@Bean
@Profile({"dev","test"})// 设置 dev test 环境开启
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
performanceInterceptor.setMaxTime(1000);
performanceInterceptor.setFormat(true);
return performanceInterceptor;
}
/**
* 数据源配置,配置多个数据源。使用配置文件,配合DRUID数据源配置类,自动装配数据源。
*/
@Bean(name = "datasource1")
@ConfigurationProperties(prefix = "spring.commons.datasource1" )
public DataSource db1() {
log.info("开始加载数据源1");
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "datasource2")
@ConfigurationProperties(prefix = "spring.commons.datasource2" )
public DataSource db2() {
log.info("开始加载数据源2");
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "datasource3")
@ConfigurationProperties(prefix = "spring.commons.datasource3" )
public DataSource db3() {
log.info("开始加载数据源3");
return DruidDataSourceBuilder.create().build();
}
/**************************************/
/**
* 动态数据源配置 将上面配置的多个数据源,设置到多数据源关联配置中
* @return
*/
@Bean
@Primary
public DataSource multipleDataSource(@Qualifier("datasource1") DataSource db1,
@Qualifier("datasource2") DataSource db2,
@Qualifier("datasource3") DataSource db3) {
log.info("开始添加数据源到适配器");
//多数据源关联类 new出来的对象是单例的,对应单独的数据源配置类---》5
MultipleDataSource multipleDataSource = new MultipleDataSource();
//将多数据源存在map中,后续进行切换配置
Map< Object, Object > targetDataSources = new HashMap<>();
targetDataSources.put(DataSourceEnum.DB1.getValue(), db1);
targetDataSources.put(DataSourceEnum.DB2.getValue(), db2);
targetDataSources.put(DataSourceEnum.DB3.getValue(), db3);
//添加数据源 添加到数据源中
multipleDataSource.setTargetDataSources(targetDataSources);
//设置默认数据源
multipleDataSource.setDefaultTargetDataSource(db1);
log.info("数据源适配器配置完成");
return multipleDataSource;
}
/**
* 数据库连接池工厂,设置的数据源是关联过后的多数据源。
*/
@Bean("sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory() throws Exception {
log.info("整理数据源工厂");
MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
log.info("设置数据源");
sqlSessionFactory.setDataSource(multipleDataSource(db1(),db2(),db3()));
//sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/*/*Mapper.xml"));
MybatisConfiguration configuration = new MybatisConfiguration();
//configuration.setDefaultScriptingLanguage(MybatisXMLLanguageDriver.class);
configuration.setJdbcTypeForNull(JdbcType.NULL);
configuration.setMapUnderscoreToCamelCase(true);
configuration.setCacheEnabled(false);
sqlSessionFactory.setConfiguration(configuration);
sqlSessionFactory.setPlugins(new Interceptor[]{ //PerformanceInterceptor(),OptimisticLockerInterceptor()
paginationInterceptor() //添加分页功能
});
// sqlSessionFactory.setGlobalConfig(globalConfiguration());
log.info("数据源工厂完毕");
return sqlSessionFactory.getObject();
}
/*@Bean
public GlobalConfiguration globalConfiguration() {
GlobalConfiguration conf = new GlobalConfiguration(new LogicSqlInjector());
conf.setLogicDeleteValue("-1");
conf.setLogicNotDeleteValue("1");
conf.setIdType(0);
//conf.setMetaObjectHandler(new MyMetaObjectHandler());
conf.setDbColumnUnderline(true);
conf.setRefresh(true);
return conf;
}*/
}