SpringBoot使用AOP完成多数据源切换

基于上个项目完成数据源配置。

1、修改pom.xml文件,加入AOP和Processor

<!-- AOP -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!--Properties动态注入 -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-configuration-processor</artifactId>
	<optional>true</optional>
</dependency>

2、修改application.properties文件

#修改tomcat端口为80
server.port=80
#设置Tomcat编码
server.tomcat.uri-encoding=UTF-8
#MyBatis配置
mybatis.config-location=classpath:mybatis/mybatis-cfg.xml  
mybatis.type-aliases-package=com.example.demo.pojo
mybatis.mapper-locations=classpath*:/com/example/demo/mapper/*.xml
#数据库连接池配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.druid.initial-size = 5
spring.datasource.druid.max-active = 20
spring.datasource.druid.min-idle = 5
spring.datasource.druid.max-wait= 30000
#数据库1配置
spring.datasource.one.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.one.url=jdbc:mysql://127.0.0.1:3306/database_one
spring.datasource.one.username=root
spring.datasource.one.password=root
#数据库2配置
spring.datasource.two.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.two.url=jdbc:mysql://127.0.0.1:3306/database_two
spring.datasource.two.username=root
spring.datasource.two.password=root

3、编写切面DynamicDataSourceAspect.java

package com.example.demo.common.aspect;

import java.lang.reflect.Method;
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.springframework.stereotype.Component;
import com.example.demo.common.config.DynamicDataSourceHolder;
import com.example.demo.common.config.TargetDataSource;


/**
 * 
 * @ClassName: DynamicDataSourceAspect
 * @Description: TODO(定义切面用于切换数据源)
 * @author willdas
 * @date 2018年9月12日 下午5:51:46
 *
 */
@Aspect
@Component
public class DynamicDataSourceAspect {

	@Pointcut("@annotation(com.example.demo.common.config.TargetDataSource)")
	public void point() {
	}

	@Pointcut("execution(public * com.example.demo.*.service..*.*(..))")
	public void excudeService() {
	}

	@Around(value = "point()&&excudeService()")
	public Object around(ProceedingJoinPoint pjp) throws Throwable {
		MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
		Method targetMethod = methodSignature.getMethod();
		if (targetMethod.isAnnotationPresent(TargetDataSource.class)) {
			String targetDataSource = targetMethod.getAnnotation(TargetDataSource.class).dataSource();
			DynamicDataSourceHolder.setDataSource(targetDataSource);
		}
		Object result = pjp.proceed();// 执行方法
		DynamicDataSourceHolder.clearDataSource();
		return result;
	}
}

4、编写DruidDataSourceConfig.java

package com.example.demo.common.config;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

/**
 * 
 * @ClassName: DruidDataSourceConfig
 * @Description: TODO(多数据源切换)
 * @author willdas
 * @date 2018年9月11日 下午2:50:12
 *
 */
@Configuration
@MapperScan(basePackages = "com.example.demo.*.dao", sqlSessionFactoryRef = "sqlSessionFactory")
public class DruidDataSourceConfig {

	/**
	 * 配置别名
	 */
	@Value("${mybatis.type-aliases-package}")
    private String typeAliasesPackage;
	
	/**
	 * 配置mapper的扫描,找到所有的mapper.xml映射文件
	 */
	@Value("${mybatis.mapper-locations}")
    private String mapperLocations;
	
	/**
	 * 加载全局的配置文件
	 */
    @Value("${mybatis.config-location}")
    private String configLocation;
	
        /**
	 * 数据源1
	 */
	@Bean(name = "oneDataSource")
	@ConfigurationProperties(prefix = "spring.datasource.one")
	public DataSource dataSourceOne() {
		return DruidDataSourceBuilder.create().build();
	}
	
	/**
	 * 数据源2
	 */
	@Bean(name = "twoDataSource")
	@ConfigurationProperties(prefix = "spring.datasource.two")
	public DataSource dataSourceTwo() {
		return DruidDataSourceBuilder.create().build();
	}
	
	/**
	 * 数据源管理
	 */
	@Bean
	public DataSource dynamicDataSource() throws SQLException {
		DynamicDataSource dynmicDataSource = new DynamicDataSource();
		Map<Object, Object> targetDataSources = new HashMap<>();
		targetDataSources.put("oneDataSource", dataSourceOne());
		targetDataSources.put("twoDataSource", dataSourceTwo());
		dynmicDataSource.setTargetDataSources(targetDataSources);
		dynmicDataSource.setDefaultTargetDataSource(dataSourceOne());  //设置默认数据源
		return dynmicDataSource;
	}
	
	/**
	 * SqlSessionFactory
	 */
	@Bean
	public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource")DataSource dataSource) throws Exception {
		SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
		sqlSessionFactoryBean.setDataSource(dataSource);
		sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations));
		sqlSessionFactoryBean.setTypeAliasesPackage(typeAliasesPackage);
		sqlSessionFactoryBean.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));
		return sqlSessionFactoryBean.getObject();
	}
 
	/**
	 * 事物
	 */
	@Bean
	public PlatformTransactionManager transactionManager(@Qualifier("dynamicDataSource")DataSource dataSource) {
		return new DataSourceTransactionManager(dataSource);
	}

}

5、编写DynamicDataSource.java

package com.example.demo.common.config;

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

/**
 * 
 * @ClassName: DynamicDataSource
 * @Description: TODO(根据Key切换数据源)
 * @author willdas
 * @date 2018年9月12日 下午5:21:10
 *
 */
public class DynamicDataSource extends AbstractRoutingDataSource {

	/*
	 * 根据Key返回targetDataSources
	 */
	@Override
	protected Object determineCurrentLookupKey() {
		return DynamicDataSourceHolder.getDataSource();
	}

}

6、编写DynamicDataSourceHolder.java

package com.example.demo.common.config;

import java.util.ArrayList;
import java.util.List;

/**
 * 
 * @ClassName: DynamicDataSourceHolder
 * @Description: TODO(存放数据源对应的key)
 * @author willdas
 * @date 2018年9月12日 下午5:50:00
 *
 */
public class DynamicDataSourceHolder {

	/*
	 * 线程本地环境
	 */
	private static final ThreadLocal<String> contextHolders = new ThreadLocal<String>();

	/*
	 * 数据源列表
	 */
	public static List<String> dataSourceIds = new ArrayList<String>();

	/*
	 * 设置数据源
	 */
	public static void setDataSource(String customerType) {
		contextHolders.set(customerType);
	}

	/*
	 * 获取数据源
	 */
	public static String getDataSource() {
		return (String) contextHolders.get();
	}

	/*
	 * 清除数据源
	 */
	public static void clearDataSource() {
		contextHolders.remove();
	}

	/*
	 * 判断指定DataSrouce当前是否存在
	 */
	public static boolean containsDataSource(String dataSourceId) {
		return dataSourceIds.contains(dataSourceId);
	}
}

7、编写TargetDataSource.java

package com.example.demo.common.config;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 
 * @ClassName: TargetDataSource
 * @Description: TODO(自定义切换数据源)
 * @author willdas
 * @date 2018年9月12日 上午9:29:44
 *
 */
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDataSource {
	String dataSource();
}

8、修改StudentServiceImpl.java,在修改方法加上注解切换到数据源2上

    /**
	 * 修改学生信息 (修改的是数据源2的数据)
	 */
	@TargetDataSource(dataSource = "twoDataSource")
	@Override
	public int updateByPrimaryKey(Student stu) {
		return studentMapper.updateByPrimaryKey(stu);
	}

9、修改DemoApplication.java

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@EnableTransactionManagement   //开启事务支持
@SpringBootApplication
public class DemoApplication {

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

10、整体项目目录如下:

11、先Maven clean,然后Maven install,最后右键DemoApplication.java,Run As 启动程序

12、打开Postman,开始测试

(1)先看下数据库数据

       数据库1的数据

       .

      数据库2的数据

      

(2)测试查询(查出来的是数据库1的数据):

(3)测试修改功能(数据库2中id为5的数据被修改了):

至此SpringBoot使用AOP完成多数据源切换功能完成。感谢阅读。共同进步

 

 

 

 

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值