您好,登錄后才能下訂單哦!
這篇文章運用了實例代碼展示springboot動態數據源的使用方法,代碼非常詳細,可供感興趣的小伙伴們參考借鑒,希望對大家有所幫助。
我們的數據庫A為主庫,其他數據庫配置在主庫中,從庫B,C,D的數量是不固定的,會根據業務的需要動態的把配置寫入到主庫中并動態在創建新的數據庫,也就是說在項目中我們只需要配置主庫的數據源,其他從庫都需要從主庫中讀出配置并動態創建數據源,動態的注入到Spring容器中,在使用的時候動態的切換數據源以實現相應的功能邏輯
Springboot:2.0.4
Mybatis-plus:3.0.7.1
JDK:1.8
在啟動類添加@Import({DynamicDataSourceRegister.class})注解用于代替默認的數據源配置
代碼結構如下:
@Component
public class ApplicationContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContextUtil.applicationContext = applicationContext;
}
/**
* 取得存儲在靜態變量中的ApplicationContext.
*/
public static ApplicationContext getApplicationContext() {
checkApplicationContext();
return applicationContext;
}
/**
* 從靜態變量ApplicationContext中取得Bean, 自動轉型為所賦值對象的類型.
*/
public static <T> T getBean(String name) {
checkApplicationContext();
if (applicationContext.containsBean(name)) {
return (T) applicationContext.getBean(name);
}
return null;
}
/**
* 從靜態變量ApplicationContext中取得Bean, 自動轉型為所賦值對象的類型.
*/
public static <T> T getBean(Class<T> clazz) {
checkApplicationContext();
return (T) applicationContext.getBeansOfType(clazz);
}
private static void checkApplicationContext() {
if (applicationContext == null)
throw new IllegalStateException("applicaitonContext未注入,請在applicationContext.xml中定義SpringContextUtil");
}
public synchronized static void registerSingletonBean(String beanName,Class clzz,Map<String,Object> original) {
checkApplicationContext();
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) ApplicationContextUtil.getApplicationContext().getAutowireCapableBeanFactory();
if(beanFactory.containsBean(beanName)){
removeBean(beanName);
}
GenericBeanDefinition definition = new GenericBeanDefinition();
//類class
definition.setBeanClass(clzz);
//屬性賦值
definition.setPropertyValues(new MutablePropertyValues(original));
//注冊到spring上下文
beanFactory.registerBeanDefinition(beanName, definition);
}
public synchronized static void registerSingletonBean(String beanName, Object obj, Map<String,Object> original) {
checkApplicationContext();
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) ApplicationContextUtil.getApplicationContext().getAutowireCapableBeanFactory();
if(beanFactory.containsBean(beanName)){
removeBean(beanName);
}
GenericBeanDefinition definition = new GenericBeanDefinition();
//類class
definition.setBeanClass(obj.getClass());
//屬性賦值
definition.setPropertyValues(new MutablePropertyValues(original));
//注冊到spring上下文
beanFactory.registerBeanDefinition(beanName, definition);
}
public synchronized static void registerSingletonBean(String beanName,Object obj) {
registerSingletonBean(beanName,obj,BeanUtils.transBean2Map(obj));
}
/**
* 刪除spring中管理的bean
* @param beanName
*/
public static void removeBean(String beanName){
ApplicationContext ctx = ApplicationContextUtil.getApplicationContext();
DefaultListableBeanFactory acf = (DefaultListableBeanFactory) ctx.getAutowireCapableBeanFactory();
if(acf.containsBean(beanName)) {
acf.removeBeanDefinition(beanName);
}
}
}
public class BeanUtils {
public static Map<String, Object> transBean2Map(Object obj) {
if(obj == null){
return null;
}
Map<String, Object> map = new HashMap<>();
try {
BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor property : propertyDescriptors) {
String key = property.getName();
// 過濾class屬性
if (!key.equals("class")) {
// 得到property對應的getter方法
Method getter = property.getReadMethod();
Object value = getter.invoke(obj);
map.put(key, value);
}
}
} catch (IntrospectionException | InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
return map;
}
}
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceContextHolder.getDataSourceType();
}
public void updateTargetDataSource(Map<String,DataSource> customDataSources){
Map<Object,Object> customDS=new HashMap<Object, Object>();
customDS.putAll(customDataSources);
setTargetDataSources(customDS);
afterPropertiesSet();
}
}
public class DynamicDataSourceContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
public static List<String> dataSourceIds = new ArrayList<>();
public static String getDataSourceType() {
return contextHolder.get();
}
public static void setDataSourceType(String dataSourceType) {
if(!containsDataSource(dataSourceType)){
DynamicDataSourceRegister.addSlaveDataSource(dataSourceType);
}
contextHolder.set(dataSourceType);
}
public static void clearDataSourceType() {
contextHolder.remove();
}
/**
* 判斷指定DataSrouce當前是否存在
*/
public static boolean containsDataSource(String dataSourceId) {
return dataSourceIds.contains(dataSourceId);
}
}
public class DynamicDataSourceRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware {
private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceRegister.class);
//默認數據源
public static DataSource defaultDataSource;
//用戶自定義數據源
public static Map<String, DataSource> slaveDataSources = new HashMap<>();
public static BeanDefinitionRegistry beanDefinitionRegistry=null;
public static String driverName;
public static String userName;
public static String password;
public static String type;
public static String url;
@Override
public void setEnvironment(Environment environment) {
initDefaultDataSource(environment);
}
private void initDefaultDataSource(Environment env) {
// 讀取主數據源
driverName=env.getProperty("spring.datasource.driver-class-name");
userName=env.getProperty("spring.datasource.username");
password=env.getProperty("spring.datasource.password");
type=env.getProperty("spring.datasource.type");
url=env.getProperty("spring.datasource.url");
Constant.defaultDbName="a";
Map<String, Object> dsMap = new HashMap<>();
dsMap.put("driver",driverName);
dsMap.put("url",url);
dsMap.put("username",userName);
dsMap.put("password",password);
dsMap.put("type",type);
defaultDataSource = buildDataSource(dsMap);
}
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
DynamicDataSourceContextHolder.dataSourceIds.add("dataSource");
Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
//添加默認數據源
targetDataSources.put("dataSource", this.defaultDataSource);
this.beanDefinitionRegistry=beanDefinitionRegistry;
beanDefinitionRegistry(defaultDataSource,targetDataSources);
logger.info("Dynamic DataSource Registry");
}
public static void addSlaveDataSource(String dataSourceType){
BeanDefinition beanDefinition=beanDefinitionRegistry.getBeanDefinition("dataSource");
PropertyValue propertyValue=beanDefinition.getPropertyValues().getPropertyValue("targetDataSources");
Map<String,DataSource> oldTargetDataSource=(Map<String,DataSource>) propertyValue.getValue();
String newUrl=firstStr+dataSourceType+secondStr;
Map<String, Object> dsMap = new HashMap<>();
dsMap.put("driver",driverName);
dsMap.put("url",newUrl);
dsMap.put("username",userName);
dsMap.put("password",password);
dsMap.put("type",type);
DataSource ds = buildDataSource(dsMap);
oldTargetDataSource.put(dataSourceType,ds);
DynamicDataSource dynamicDataSource =ApplicationContextUtil.getBean("dataSource");
dynamicDataSource.updateTargetDataSource(oldTargetDataSource);
DynamicDataSourceContextHolder.dataSourceIds.add(dataSourceType);
}
public void beanDefinitionRegistry(DataSource defaultDataSource,Map<Object,Object> targetDataSources){
//創建DynamicDataSource
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(DynamicDataSource.class);
beanDefinition.setSynthetic(true);
MutablePropertyValues mpv = beanDefinition.getPropertyValues();
mpv.addPropertyValue("defaultTargetDataSource", defaultDataSource);
if(targetDataSources.size()>0){
mpv.addPropertyValue("targetDataSources", targetDataSources);
}
//注冊 - BeanDefinitionRegistry
beanDefinitionRegistry.registerBeanDefinition("dataSource", beanDefinition);
}
public static DataSource buildDataSource(Map<String, Object> dataSourceMap) {
try {
Object type = dataSourceMap.get("type");
Class<? extends DataSource> dataSourceType;
dataSourceType = (Class<? extends DataSource>) Class.forName((String) type);
String driverClassName = dataSourceMap.get("driver").toString();
String url = dataSourceMap.get("url").toString();
String username = dataSourceMap.get("username").toString();
String password = dataSourceMap.get("password").toString();
// 自定義DataSource配置
DataSourceBuilder factory = DataSourceBuilder.create().driverClassName(driverClassName).url(url)
.username(username).password(password).type(dataSourceType);
return factory.build();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
DynamicDataSourceContextHolder.setDataSourceType("B");
Integer lProductUv=dataVisitCollectionMapper.getProductUv(dDate);
DynamicDataSourceContextHolder.setDataSourceType(Constant.defaultDbName);
在setDataSourceType的時候判斷是否存在此數據源,如果存在就直接切換,不存在就動態創建并加入到Spring容器中,從而實現動態創建數據源的目的
關于springboot動態數據源的使用就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。