mirror of
http://git.pig4cloud.com/pig/pigx.git
synced 2026-11-15 06:29:01 +08:00
✨ 添加新特性。pigx 动态切换数据源,为后期提供Online开发、数据同步以及读写分离做准备
This commit is contained in:
1 parent
6eaa933fde
commit
896dbdeb40
12 files changed
+221
-15
No files matched your search
+16
@@ -0,0 +1,16 @@
|
||||
package com.pig4cloud.pigx.common.datasource;
|
||||
|
||||
import com.pig4cloud.pigx.common.datasource.config.DruidDataSourceProperties;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
|
||||
/**
|
||||
* @author Lucky
|
||||
* @date 2019-05-18
|
||||
* <p>
|
||||
* DbAcess 自动配置类
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@EnableConfigurationProperties({DruidDataSourceProperties.class})
|
||||
public class DataSourceAutoConfiguration {
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.pig4cloud.pigx.common.datasource.annotation;
|
||||
|
||||
import com.pig4cloud.pigx.common.datasource.config.DynamicDataSourceConfig;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @author Lucky
|
||||
* @date 2019-05-18
|
||||
* <p>
|
||||
* 开启动态数据源
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
@Import({DynamicDataSourceConfig.class})
|
||||
public @interface EnableDynamicDataSource {
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.pig4cloud.pigx.common.datasource.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @date 2019-05-14
|
||||
* <p>
|
||||
* 参考DruidDataSourceWrapper
|
||||
*/
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties("spring.datasource.druid")
|
||||
public class DruidDataSourceProperties {
|
||||
private String username;
|
||||
private String password;
|
||||
private String url;
|
||||
private String driverClassName;
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package com.pig4cloud.pigx.common.datasource.config;
|
||||
|
||||
import com.pig4cloud.pigx.common.datasource.support.DynamicDataSourceContextHolder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @date 2019-03-31
|
||||
* <p>
|
||||
* 动态数据源类
|
||||
*/
|
||||
@Slf4j
|
||||
public class DynamicDataSource extends AbstractRoutingDataSource {
|
||||
|
||||
/**
|
||||
* 指定路由Key
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected Object determineCurrentLookupKey() {
|
||||
return DynamicDataSourceContextHolder.getDataSourceType();
|
||||
}
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
package com.pig4cloud.pigx.common.datasource.config;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.PostConstruct;
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.mysql.cj.jdbc.Driver;
|
||||
import com.pig4cloud.pigx.common.datasource.support.DataSourceConstants;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jasypt.encryption.StringEncryptor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||
import org.springframework.jdbc.datasource.DriverManagerDataSource;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @date 2019-03-31
|
||||
* <p>
|
||||
* 动态数据源切换配置
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@AllArgsConstructor
|
||||
public class DynamicDataSourceConfig implements TransactionManagementConfigurer {
|
||||
private final Map<Object, Object> dataSourceMap = new HashMap<>(8);
|
||||
private final DruidDataSourceProperties dataSourceProperties;
|
||||
private final StringEncryptor stringEncryptor;
|
||||
|
||||
@Bean("dynamicDataSource")
|
||||
public DynamicDataSource dataSource() {
|
||||
DynamicDataSource ds = new DynamicDataSource();
|
||||
DruidDataSource cads = new DruidDataSource();
|
||||
cads.setUrl(dataSourceProperties.getUrl());
|
||||
cads.setDriverClassName(dataSourceProperties.getDriverClassName());
|
||||
cads.setUsername(dataSourceProperties.getUsername());
|
||||
cads.setPassword(dataSourceProperties.getPassword());
|
||||
ds.setDefaultTargetDataSource(cads);
|
||||
dataSourceMap.put(0, cads);
|
||||
ds.setTargetDataSources(dataSourceMap);
|
||||
return ds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 组装默认配置的数据源,查询数据库配置
|
||||
*/
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
DriverManagerDataSource dds = new DriverManagerDataSource();
|
||||
dds.setUrl(dataSourceProperties.getUrl());
|
||||
dds.setDriverClassName(dataSourceProperties.getDriverClassName());
|
||||
dds.setUsername(dataSourceProperties.getUsername());
|
||||
dds.setPassword(dataSourceProperties.getPassword());
|
||||
|
||||
List<Map<String, Object>> dbList = new JdbcTemplate(dds).queryForList(DataSourceConstants.QUERY_DS_SQL);
|
||||
log.info("开始 -> 初始化动态数据源");
|
||||
Optional.of(dbList).ifPresent(list -> list.forEach(db -> {
|
||||
log.info("数据源:{}", db.get(DataSourceConstants.DS_NAME));
|
||||
DruidDataSource ds = new DruidDataSource();
|
||||
ds.setUrl(String.valueOf(db.get(DataSourceConstants.DS_JDBC_URL)));
|
||||
ds.setDriverClassName(Driver.class.getName());
|
||||
ds.setUsername((String) db.get(DataSourceConstants.DS_USER_NAME));
|
||||
|
||||
String decPwd = stringEncryptor.decrypt((String) db.get(DataSourceConstants.DS_USER_PWD));
|
||||
ds.setPassword(decPwd);
|
||||
dataSourceMap.put(db.get(DataSourceConstants.DS_ROUTE_KEY), ds);
|
||||
}));
|
||||
|
||||
log.info("完毕 -> 初始化动态数据源,共计 {} 条", dataSourceMap.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新加载数据源配置
|
||||
*/
|
||||
public Boolean reload() {
|
||||
init();
|
||||
DynamicDataSource dataSource = dataSource();
|
||||
dataSource.setTargetDataSources(dataSourceMap);
|
||||
dataSource.afterPropertiesSet();
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public PlatformTransactionManager txManager() {
|
||||
return new DataSourceTransactionManager(dataSource());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformTransactionManager annotationDrivenTransactionManager() {
|
||||
return txManager();
|
||||
}
|
||||
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package com.pig4cloud.pigx.common.datasource.config;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import com.pig4cloud.pigx.common.datasource.support.DynamicDataSourceContextHolder;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.redis.core.HashOperations;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @date 2019-05-18
|
||||
* <p>
|
||||
* 动态数据源拦截器
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@AllArgsConstructor
|
||||
public class DynamicDatasourceInterceptor implements HandlerInterceptor {
|
||||
private final RedisTemplate redisTemplate;
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
|
||||
redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(String.class));
|
||||
HashOperations<String, String, String> vo = redisTemplate.opsForHash();
|
||||
// String dbName = vo.get("db_route_key", 1);
|
||||
DynamicDataSourceContextHolder.setDataSourceType(1);
|
||||
log.info("数据源切换:{}", 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
|
||||
@Nullable Exception ex) {
|
||||
DynamicDataSourceContextHolder.clearDataSourceType();
|
||||
}
|
||||
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package com.pig4cloud.pigx.common.datasource.support;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @date 2019-04-01
|
||||
* <p>
|
||||
* 数据源相关常量
|
||||
*/
|
||||
public interface DataSourceConstants {
|
||||
/**
|
||||
* 查询数据源的SQL
|
||||
*/
|
||||
String QUERY_DS_SQL = "select * from sys_datasource_conf where del_flag = 0";
|
||||
|
||||
/**
|
||||
* 动态路由KEY
|
||||
*/
|
||||
String DS_ROUTE_KEY = "id";
|
||||
|
||||
/**
|
||||
* 数据源名称
|
||||
*/
|
||||
String DS_NAME = "name";
|
||||
|
||||
/**
|
||||
* jdbcurl
|
||||
*/
|
||||
String DS_JDBC_URL = "url";
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
String DS_USER_NAME = "username";
|
||||
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
String DS_USER_PWD = "password";
|
||||
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package com.pig4cloud.pigx.common.datasource.support;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @date 2019-05-18
|
||||
* <p>
|
||||
* 根据当前线程来选择具体的数据源
|
||||
*/
|
||||
@UtilityClass
|
||||
public class DynamicDataSourceContextHolder {
|
||||
private final ThreadLocal<Integer> CONTEXT_HOLDER = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* 提供给AOP去设置当前的线程的数据源的信息
|
||||
*
|
||||
* @param dataSourceType
|
||||
*/
|
||||
public void setDataSourceType(Integer dataSourceType) {
|
||||
CONTEXT_HOLDER.set(dataSourceType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 提供给AbstractRoutingDataSource的实现类,通过key选择数据源
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Integer getDataSourceType() {
|
||||
return CONTEXT_HOLDER.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用默认的数据源
|
||||
*
|
||||
*/
|
||||
public void clearDataSourceType() {
|
||||
CONTEXT_HOLDER.remove();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
com.pig4cloud.pigx.common.datasource.DataSourceAutoConfiguration
|
||||
Reference in new issue
Block a user