通过AOP实现动态数据源切换

1. 自定义注解

  • 默认值ds1,即默认数据源是ds1
import java.lang.annotation.*;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetSource {
    String value() default "ds1";
}

2. 创建DynamicDataSourceHolder类,存在数据源名称

public class DynamicDataSourceHolder {
    private static ThreadLocal<String> local = new ThreadLocal<>();

    public static String getDs() {
        return local.get();
    }

    public static ThreadLocal getLocal(){
        return local;
    }
}

3. 创建DynamicDataSource类,获取数据源名称

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

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
    	// 从ThreadLocal中拿到数据源名称,数据源名是通过aop拦截注解时,把数据源名称存进去的
        String ds = DynamicDataSourceHolder.getDs();
        System.out.println("=========选择的数据源:" + ds);
        return ds;
    }
}

4. 创建切面类AspectDs,拦截自定义的注解

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Aspect
@Order(-1)
public class AspectDs {

    @Before(value = "@annotation(targetSource)")
    public void dataSource(TargetSource targetSource) {

        String value = targetSource.value();
        if(value != null && !"".equals(value)) {
        	// 1.如果注解上定义了数据源,使用自定义的
            DynamicDataSourceHolder.getLocal().set(value);
            System.out.println("========AspectDs:"+value);
        } else {
        	// 2.如果没有自定义数据库,使用默认数据源
            System.out.println("========AspectDs:ds1");
            DynamicDataSourceHolder.getLocal().set("ds1");
        }
    }
}

5. 创建数据源配置类DataSourceConfiguration

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

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

@Configuration
@PropertySource("classpath:jdbc.properties")
public class DataSourceConfiguration {
    @Value("${db.driverClassName}")
    private String driverClass;
    @Value("${db.url}")
    private String jdbcUrl;
     @Value("${db.url2}")
    private String jdbcUrl2;
    @Value("${db.username}")
    private String username;
    @Value("${db.password}")
    private String password;

	// 1.数据源ds1
    public DataSource getDs1(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName(driverClass);
        druidDataSource.setUrl(jdbcUrl);
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);
        druidDataSource.setMaxActive(2);
        druidDataSource.setInitialSize(2);
        druidDataSource.setTimeBetweenConnectErrorMillis(60000);
        druidDataSource.setMinEvictableIdleTimeMillis(300000);
        druidDataSource.setValidationQuery("SELECT 1 FROM DUAL");
        druidDataSource.setTestWhileIdle(true);
        druidDataSource.setTestOnBorrow(false);
        druidDataSource.setTestOnReturn(false);
        druidDataSource.setPoolPreparedStatements(true);
        druidDataSource.setMaxPoolPreparedStatementPerConnectionSize(20);
        try {
            druidDataSource.setFilters("stat,wall");
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return druidDataSource;
    }
    // 2.数据源ds2
    public DataSource getDs2(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName(driverClass);
        druidDataSource.setUrl(jdbcUrl2);
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);
        druidDataSource.setMaxActive(2);
        druidDataSource.setInitialSize(2);
        druidDataSource.setTimeBetweenConnectErrorMillis(60000);
        druidDataSource.setMinEvictableIdleTimeMillis(300000);
        druidDataSource.setValidationQuery("SELECT 1 FROM DUAL");
        druidDataSource.setTestWhileIdle(true);
        druidDataSource.setTestOnBorrow(false);
        druidDataSource.setTestOnReturn(false);
        druidDataSource.setPoolPreparedStatements(true);
        druidDataSource.setMaxPoolPreparedStatementPerConnectionSize(20);
        try {
            druidDataSource.setFilters("stat,wall");
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return druidDataSource;
    }

    @Bean
    public DataSource dynamicDataSource() {
        Map<Object, Object> targetDataSources = new HashMap<>();
        DataSource ds1 = getDs1();
        DataSource ds2 = getDs2();
        targetDataSources.put("ds1", ds1);
        targetDataSources.put("ds2", ds2);
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        // 3.把创建的2个数据源添加到数据源对象中
        dynamicDataSource.setTargetDataSources(targetDataSources);
        // 4.把ds1设置为默认数据源
        dynamicDataSource.setDefaultTargetDataSource(ds1);
        return dynamicDataSource;
    }

}

6. 在方法上添加@TargetSource

  • 使用ds2数据源,aop会自动拦截到此注解并使用ds2查询数据
@TargetSource(value = "ds2")
public User findUserById(String id) {
	return (User) this.getObjectById(User.class, id);
}
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值