最近在研究Spring Cloud搭建微服务相关,对于一个庞大的系统,需要拆分为多个微服务,每个服务相当于一个模块,负责不同的事情,各司其职,当然,数据库之间也需要保持相对独立,这样就需要涉及到多个数据库,那么,如何使用Spring Boot配置多数据源呢?
首先,我们需要一个自定义注解,命名为:DataSource
@Retention(RetentionPolicy.RUNTIME)//将该注解定义在运行时级别
@Target(ElementType.METHOD)//将该注解应用于方法上
public @interface DataSource {
String value() default "user";
}
然后创建数据源的类: DynamicDataSourceHolder
public class DynamicDataSourceHolder {
/**
* 默认数据源
*
*/
public static final String DEFAULT_DATASOURCE = "user";
public static final ThreadLocal<String> holder = new ThreadLocal<String>();
public static void setDataSource(String name) {
holder.set(name);
}
public static String getDataSouce() {
return holder.get();
}
public static void clearDataSouce() {
holder.remove();
}
}
配置动态数据源的类: DynamicDataSource
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceHolder.getDataSouce();
}
}
然后我们生成数据源,创建 MybatisConfig类
@Configuration
@PropertySource("classpath:jdbc.properties") //引入配置文件jdbc.properties中的信息
@MapperScan(basePackages ={"com.drive.dbuser.dao"} , sqlSessionFactoryRef = "sqlSessionFactory") // 配置Mapper作用的位置
public class MybatisConfig {
@Bean(name = "user")
@ConfigurationProperties(prefix = "user")
public DataSource dataSourceUser(){
return DataSourceBuilder.create().build();
} //生成user数据源
@Bean(name = "drive")
@ConfigurationProperties(prefix = "drive")
public DataSource dataSourceDrive(){
return DataSourceBuilder.create().build();
} //生成drive数据源
@Bean(name = "order")
@ConfigurationProperties(prefix = "order")
public DataSource dataSourceOrder(){
return DataSourceBuilder.create().build();
} //生成order数据源
@Bean(name = "dynamicDataSource")
public DataSource dataSource(){
DynamicDataSource dynamicDataSource = new DynamicDataSource();
// 默认数据源---User
dynamicDataSource.setDefaultTargetDataSource(dataSourceUser());
// 配置多数据源
Map<Object, Object> dataSourceMap = new HashMap(5);
dataSourceMap.put("user", dataSourceUser());
dataSourceMap.put("drive", dataSourceDrive());
dataSourceMap.put("order", dataSourceOrder());
dynamicDataSource.setTargetDataSources(dataSourceMap);
return dynamicDataSource;
} //配置多数据源
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource()); //
//添加XML目录
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
factoryBean.setMapperLocations(resolver.getResources("classpath*:com/drive/dbuser/mapper/*.xml")); //生效的位置
return factoryBean.getObject();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}//创建Session工厂
/* @Bean
public SqlSessionTemplate sqlSessionTemplate() throws Exception { //SqlSessionTemplate 是 MyBatis-Spring 的核心。 这个类负责管理 MyBatis 的 SqlSession, 调用 MyBatis 的 SQL 方法
SqlSessionTemplate template = new SqlSessionTemplate(sqlSessionFactory()); // 使用上面配置的Factory
return template;
}*/
}
我们来看一下 jdbc.properties的配置文件的信息:
#用户服务库
user.url=jdbc:mysql:***
user.username=***
user.password=***
#打车服务库
drive.url=
drive.username=
drive.password=
#订单服务库
order.url=
order.username=
order.password=
user.driverClassName=com.mysql.jdbc.Driver
drive.driverClassName=com.mysql.jdbc.Driver
order.driverClassName=com.mysql.jdbc.Driver
这样我们的多数据源都配置好了,那么如何调用呢,比如说我需要先去user数据库里查数据,然后再去drive数据库里添加数据,这样怎么动态的更换数据源呢?
我们可以使用Spring 中的一大核心AOP,首先我们需要在application.properties文件中开启AOP
spring.aop.auto=true
#开启AOP
然后创建 DataSourceAspect类,
@Aspect
@Component
public class DataSourceAspect {
@Pointcut("execution(* com.drive.dbuser.dao.*.*(..))")
public void declareJointPointExpression() {
}
@Before("declareJointPointExpression()")
public void beforeSwitchDS(JoinPoint point){
//获得当前访问的class
Class<?>[] className = point.getTarget().getClass().getInterfaces();
//获得访问的方法名
String methodName = point.getSignature().getName();
//得到方法的参数的类型
Class[] argClass = ((MethodSignature)point.getSignature()).getParameterTypes();
String dataSource = DynamicDataSourceHolder.DEFAULT_DATASOURCE;
try {
// 得到访问的方法对象
Method method = className[0].getMethod(methodName, argClass);
// 判断是否存在@DataSource注解
if (method.isAnnotationPresent(DataSource.class)) {
DataSource annotation = method.getAnnotation(DataSource.class);
// 取出注解中的数据源名
dataSource = annotation.value();
}
} catch (Exception e) {
e.printStackTrace();
}
// 切换数据源
DynamicDataSourceHolder.setDataSource(dataSource);
}
@After("declareJointPointExpression()")
public void afterSwitchDS(JoinPoint point){
DynamicDataSourceHolder.clearDataSouce();
}
}
这时,我们再看一下关于Dao层的内容:
@DataSource("user")
List<CustomerVO> selectCustomer(CustomerVO customerVO);
我们创建一个切面类,当我们调用Dao层之前,会首先查看在Mapper 接口上方法上的注解,并将它作为数据源,注入到DynamicDataSourceHolder中,这样,就可以实现动态切换数据源了。
最后,我们在启动类上需要加上
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class}) //通过禁用指定的自动化配置来避免加载不必要的自动化配置
@EnableConfigurationProperties //注解是用来开启对@ConfigurationProperties注解配置Bean的支持, 该注解告诉Spring Boot 使能支持@ConfigurationProperties:注解主要用来把properties配置文件转化为bean来使用
当然,不要忘了在pom.xml中配置所需要的依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- Spring Boot Mybatis 依赖 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<!-- MySQL 连接驱动依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.4</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.12</version>
</dependency>
<!--log4j-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
好了,大功告成了,喜欢的朋友们记得关注我一下!