2、多数据源配置之自定义注解aop拦截进行配置
前言
其实这里可以使用很多库的,但是我这里却只用了2个库,一个库one作为默认库,另一个库作为指定库,当然one库也可以指定。先提供给类注解,如果方法上有注解则先看方法里面的
1、自定义注解
package com.hlj.many.datasourse.data;
/**
* @Description 自定义注解
* @Date 2018/4/24 下午6:09.
*/
public enum DataSource {
ONE("one"),
TWO("two"),
;
private String name;
DataSource(String name){
this.name = name;
}
public String getName(){
return this.name;
}
}
2、配置数据源信息
server.port=8888
########################################################
### jpa
########################################################
spring.jpa.database=MYSQL
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto =update
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
# 主数据源
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url=jdbc:mysql://localhost:3306/com_hlj_many_database-one
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
# 其他数据源
hlj.datasource.names=one,two
#datasource one
hlj.datasource.one.type=com.alibaba.druid.pool.DruidDataSource
hlj.datasource.one.url=jdbc:mysql://localhost:3306/com_hlj_many_database-one
hlj.datasource.one.username=root
hlj.datasource.one.password=123456
hlj.datasource.one.driver-class-name=com.mysql.jdbc.Driver
#datasource two
hlj.datasource.two.type=com.alibaba.druid.pool.DruidDataSource
hlj.datasource.two.url=jdbc:mysql://localhost:3306/com_hlj_many_database-two
hlj.datasource.two.username=root
hlj.datasource.two.password=123456
hlj.datasource.two.driver-class-name=com.mysql.jdbc.Driver
3、多个数据源的存取单例模式
package com.hlj.many.datasourse.data;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
/**
* @Description 类似于单例模式数据源
* @Date 2018/4/24 下午6:10.
*/
public class DynamicDataSourceContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
private static final ThreadLocal<Stack<String>> stackHolder = new ThreadLocal<>();
public static List<String> dataSourceIds = new ArrayList<>();
public static void setDataSource(String dataSourceType) {
// 保存当前线程上一次的数据源,用于清除时恢复上次的上线文
if (contextHolder.get() != null){
Stack<String> stack = stackHolder.get();
if (stack == null){
stack = new Stack<>();
stackHolder.set(stack);
}
stack.push(contextHolder.get());
}
contextHolder.set(dataSourceType);
}
public static String getDataSourceType() {
return contextHolder.get();
}
public static void clearDataSource() {
// 清除本次的数据源
contextHolder.remove();
// 从栈中拿出上一次的数据源
Stack<String> stack = stackHolder.get();
if (stack != null){
if (stack.isEmpty()){
stackHolder.remove();
}else{
String pop = stack.pop();
contextHolder.set(pop);
if (stack.isEmpty()){
stackHolder.remove();
}
}
}
}
/**
* 判断指定DataSrouce当前是否存在
* @param dataSourceName
* @return
*/
public static boolean containsDataSource(String dataSourceName){
return dataSourceIds.contains(dataSourceName);
}
}
4、获取动态数据源
package com.hlj.many.datasourse.data;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* @Description 获取动态数据源
* @Date 2018/4/24 下午6:11.
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceContextHolder.getDataSourceType();
}
}
5、数据源的设置和绑定,提供给springboot启动的时候进行导入和加载
package com.hlj.many.datasourse.data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.bind.RelaxedDataBinder;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
* Created by fengchuanbo on 2017/5/8.
*/
@Slf4j
public class DynamicDataSourceRegistrar implements ImportBeanDefinitionRegistrar,EnvironmentAware {
private ConversionService conversionService = new DefaultConversionService();
private PropertyValues dataSourcePropertyValues;
// 如配置文件中未指定数据源类型,使用该默认值
private static final Object DATASOURCE_TYPE_DEFAULT = "org.apache.tomcat.jdbc.pool.DataSource";
// 数据源
private DataSource defaultDataSource;
private Map<String, DataSource> customDataSources = new HashMap<>();
private static final String DEFAULT_DATASOURCE_NAME = com.hlj.many.datasourse.data.DataSource.ONE.getName();
@Override
public void setEnvironment(Environment environment) {
initDefaultDataSource(environment);
initCustomDataSources(environment);
}
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
Map<Object, Object> targetDataSources = new HashMap<>();
// 将主数据源添加到更多数据源中
targetDataSources.put(DEFAULT_DATASOURCE_NAME, defaultDataSource);
DynamicDataSourceContextHolder.dataSourceIds.add(DEFAULT_DATASOURCE_NAME);
// 添加更多数据源
targetDataSources.putAll(customDataSources);
for (String key : customDataSources.keySet()) {
DynamicDataSourceContextHolder.dataSourceIds.add(key);
}
// 创建DynamicDataSource
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(DynamicDataSource.class);
beanDefinition.setSynthetic(true);
MutablePropertyValues mpv = beanDefinition.getPropertyValues();
mpv.addPropertyValue("defaultTargetDataSource", defaultDataSource);
mpv.addPropertyValue("targetDataSources", targetDataSources);
registry.registerBeanDefinition(DEFAULT_DATASOURCE_NAME, beanDefinition);
if (log.isInfoEnabled()) {
log.info("Dynamic DataSource Registry");
}
}
/**
* 初始化主数据源
*
* @author SHANHY
* @create 2016年1月24日
*/
private void initDefaultDataSource(Environment env) {
// 读取主数据源
RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "spring.datasource.");
Map<String, Object> dsMap = new HashMap<>();
dsMap.put("type", propertyResolver.getProperty("type"));
dsMap.put("driver-class-name", propertyResolver.getProperty("driver-class-name"));
dsMap.put("url", propertyResolver.getProperty("url"));
dsMap.put("username", propertyResolver.getProperty("username"));
dsMap.put("password", propertyResolver.getProperty("password"));
defaultDataSource = buildDataSource(dsMap);
dataBinder(defaultDataSource, env,"spring.datasource");
}
/**
* 为DataSource绑定更多数据
* @param dataSource
* @param env
*/
private void dataBinder(DataSource dataSource, Environment env, String prefix){
RelaxedDataBinder dataBinder = new RelaxedDataBinder(dataSource);
//dataBinder.setValidator(new LocalValidatorFactory().run(this.applicationContext));
dataBinder.setConversionService(conversionService);
dataBinder.setIgnoreNestedProperties(false);//false
dataBinder.setIgnoreInvalidFields(false);//false
dataBinder.setIgnoreUnknownFields(true);//true
if(dataSourcePropertyValues == null){
Map<String, Object> rpr = new RelaxedPropertyResolver(env, prefix).getSubProperties(".");
Map<String, Object> values = new HashMap<>(rpr);
// 排除已经设置的属性
values.remove("type");
values.remove("driver-class-name");
values.remove("url");
values.remove("username");
values.remove("password");
dataSourcePropertyValues = new MutablePropertyValues(values);
}
dataBinder.bind(dataSourcePropertyValues);
}
/**
* 初始化更多数据源
*/
private void initCustomDataSources(Environment env) {
// 读取配置文件获取更多数据源,也可以通过defaultDataSource读取数据库获取更多数据源
RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "hlj.datasource.");
String dsPrefixs = propertyResolver.getProperty("names");
if (StringUtils.isEmpty(dsPrefixs)) return;
for (String dsPrefix : dsPrefixs.split(",")) {// 多个数据源
Map<String, Object> dsMap = propertyResolver.getSubProperties(dsPrefix + ".");
DataSource ds = buildDataSource(dsMap);
customDataSources.put(dsPrefix, ds);
dataBinder(ds, env,"hlj.datasource." + dsPrefix);
}
}
/**
* 创建DataSource
* @return
*/
public DataSource buildDataSource(Map<String, Object> dsMap) {
try {
Object type = dsMap.get("type");
if (type == null)
type = DATASOURCE_TYPE_DEFAULT;// 默认DataSource
Class<? extends DataSource> dataSourceType;
dataSourceType = (Class<? extends DataSource>) Class.forName((String) type);
String driverClassName = dsMap.get("driver-class-name").toString();
String url = dsMap.get("url").toString();
String username = dsMap.get("username").toString();
String password = dsMap.get("password").toString();
DataSourceBuilder factory = DataSourceBuilder.create()
.driverClassName(driverClassName)
.url(url).username(username)
.password(password)
.type(dataSourceType);
return factory.build();
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
6、springBoot启动,扫描jpa和导入DynamicDataSourceRegistrar.class
package com.hlj.many.datasourse;
import com.hlj.many.datasourse.data.DynamicDataSourceRegistrar;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportResource;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@SpringBootApplication
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = {"com.hlj.many.datasourse.dataresource.dao"})
@EntityScan(basePackages = "com.hlj.many.datasourse.dataresource.dao")
@Import({DynamicDataSourceRegistrar.class}) //导入数据库
public class ComHljManyDatasourceApplication {
public static void main(String[] args) {
SpringApplication.run(ComHljManyDatasourceApplication.class, args);
}
}
7、添加mybatis
package com.hlj.many.datasourse.config;
import org.apache.commons.lang3.ArrayUtils;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import javax.sql.DataSource;
import java.io.IOException;
/**
* @Description
* @Author HealerJean
* @Date 2018/4/24 下午5:44.
*/
@Configuration
public class MybatisConfig {
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setBasePackage("com.hlj.many.datasourse.dataresource.dao.*");
return configurer;
}
@Bean
public SqlSessionFactoryBean sessionFactory(DataSource dataSource, ApplicationContext applicationContext) throws IOException {
SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource);
sessionFactoryBean.setConfigLocation(applicationContext.getResource("classpath:mybatis.xml"));
Resource[] resources = ArrayUtils.addAll(
applicationContext.getResources("classpath*:com/hlj/many/datasourse/dataresource/dao/**/*.xml")
);
sessionFactoryBean.setMapperLocations(resources);
return sessionFactoryBean;
}
}
测试方法也挺多的,如果需要请直接下载代码
下载代码
如果满意,请打赏博主任意金额,感兴趣的请下方留言吧。可与博主自由讨论哦
支付包 | 微信 | 微信公众号 |
---|---|---|