解耦atomikos
This commit is contained in:
parent
ac40c0f92f
commit
85992058e2
@ -0,0 +1,9 @@
|
||||
package com.ruoyi.common.service.datasource;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
|
||||
|
||||
public interface CreateDataSource {
|
||||
DataSource createDataSource(String name, DataSourceProperties dataSourceProperties);
|
||||
}
|
@ -1,5 +1,8 @@
|
||||
package com.ruoyi.framework.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
@ -8,7 +11,9 @@ import org.springframework.transaction.jta.JtaTransactionManager;
|
||||
|
||||
import com.atomikos.icatch.jta.UserTransactionImp;
|
||||
import com.atomikos.icatch.jta.UserTransactionManager;
|
||||
import com.atomikos.jdbc.AtomikosDataSourceBean;
|
||||
|
||||
import jakarta.annotation.PreDestroy;
|
||||
import jakarta.transaction.TransactionManager;
|
||||
import jakarta.transaction.UserTransaction;
|
||||
|
||||
@ -18,11 +23,9 @@ import jakarta.transaction.UserTransaction;
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Configuration
|
||||
public class AtomikosConfig
|
||||
{
|
||||
public class AtomikosConfig {
|
||||
@Bean(name = "userTransaction")
|
||||
public UserTransaction userTransaction() throws Throwable
|
||||
{
|
||||
public UserTransaction userTransaction() throws Throwable {
|
||||
UserTransaction userTransaction = new UserTransactionImp();
|
||||
// 设置事务超时时间为10000毫秒
|
||||
userTransaction.setTransactionTimeout(10000);
|
||||
@ -30,8 +33,7 @@ public class AtomikosConfig
|
||||
}
|
||||
|
||||
@Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close")
|
||||
public TransactionManager atomikosTransactionManager() throws Throwable
|
||||
{
|
||||
public TransactionManager atomikosTransactionManager() throws Throwable {
|
||||
UserTransactionManager userTransactionManager = new UserTransactionManager();
|
||||
// 设置是否强制关闭事务管理器为false
|
||||
userTransactionManager.setForceShutdown(false);
|
||||
@ -40,10 +42,22 @@ public class AtomikosConfig
|
||||
|
||||
@Bean(name = "transactionManager")
|
||||
@DependsOn({ "userTransaction", "atomikosTransactionManager" })
|
||||
public PlatformTransactionManager transactionManager() throws Throwable
|
||||
{
|
||||
public PlatformTransactionManager transactionManager() throws Throwable {
|
||||
UserTransaction userTransaction = userTransaction();
|
||||
TransactionManager atomikosTransactionManager = atomikosTransactionManager();
|
||||
return new JtaTransactionManager(userTransaction, atomikosTransactionManager);
|
||||
}
|
||||
|
||||
private List<AtomikosDataSourceBean> atomikosDataSourceBeans = new ArrayList<>();
|
||||
|
||||
public List<AtomikosDataSourceBean> getAtomikosDataSourceBeans() {
|
||||
return atomikosDataSourceBeans;
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void destroy() {
|
||||
for (AtomikosDataSourceBean aDataSourceBean : this.atomikosDataSourceBeans) {
|
||||
aDataSourceBean.close();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.ruoyi.framework.config;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.alibaba.druid.pool.xa.DruidXADataSource;
|
||||
import com.atomikos.jdbc.AtomikosDataSourceBean;
|
||||
import com.ruoyi.common.service.datasource.CreateDataSource;
|
||||
|
||||
@Component
|
||||
@DependsOn({ "transactionManager" })
|
||||
public class AtomikosDataSourceCreate implements CreateDataSource {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AtomikosDataSourceCreate.class);
|
||||
@Autowired
|
||||
private DynamicDataSourceProperties properties;
|
||||
|
||||
@Autowired
|
||||
private DruidConfig druidConfig;
|
||||
|
||||
@Autowired
|
||||
private AtomikosConfig atomikosConfig;
|
||||
|
||||
public DataSource createDataSource(String name, DataSourceProperties dataSourceProperties) {
|
||||
Properties prop = properties.build(dataSourceProperties);
|
||||
DruidXADataSource dataSource = new DruidXADataSource();
|
||||
druidConfig.getDruidDataSources().add(dataSource);
|
||||
dataSource.setConnectProperties(prop);
|
||||
properties.setProperties(dataSource, prop);
|
||||
AtomikosDataSourceBean ds = new AtomikosDataSourceBean();
|
||||
atomikosConfig.getAtomikosDataSourceBeans().add(ds);
|
||||
ds.setXaDataSourceClassName("com.alibaba.druid.pool.xa.DruidXADataSource");
|
||||
ds.setUniqueResourceName(name);
|
||||
ds.setXaProperties(prop);
|
||||
ds.setXaDataSource(dataSource);
|
||||
properties.validateDataSource(ds);
|
||||
logger.info("数据源:{} 链接成功", name);
|
||||
return ds;
|
||||
}
|
||||
}
|
@ -1,10 +1,8 @@
|
||||
package com.ruoyi.framework.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -13,12 +11,12 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.alibaba.druid.spring.boot3.autoconfigure.properties.DruidStatProperties;
|
||||
import com.alibaba.druid.util.Utils;
|
||||
import com.ruoyi.framework.datasource.DynamicDataSource;
|
||||
|
||||
import jakarta.annotation.PreDestroy;
|
||||
import jakarta.servlet.Filter;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
@ -36,18 +34,9 @@ public class DruidConfig {
|
||||
@Autowired
|
||||
DynamicDataSourceProperties dataSourceProperties;
|
||||
|
||||
Logger logger = LoggerFactory.getLogger(DruidConfig.class);
|
||||
private List<DruidDataSource> druidDataSources = new ArrayList<>();
|
||||
|
||||
@Bean(name = "dynamicDataSource")
|
||||
@Primary
|
||||
public DynamicDataSource dataSource() {
|
||||
Map<Object, Object> objectMap = new HashMap<>();
|
||||
Map<String, DataSource> targetDataSources = dataSourceProperties.getTargetDataSources();
|
||||
for (Map.Entry<String, DataSource> entry : targetDataSources.entrySet()) {
|
||||
objectMap.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return new DynamicDataSource(targetDataSources.get(dataSourceProperties.getPrimary()), objectMap);
|
||||
}
|
||||
Logger logger = LoggerFactory.getLogger(DruidConfig.class);
|
||||
|
||||
/**
|
||||
* 去除监控页面底部的广告
|
||||
@ -91,4 +80,15 @@ public class DruidConfig {
|
||||
registrationBean.addUrlPatterns(commonJsPattern);
|
||||
return registrationBean;
|
||||
}
|
||||
|
||||
public List<DruidDataSource> getDruidDataSources() {
|
||||
return druidDataSources;
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void destroy() {
|
||||
for (DruidDataSource druidDataSource : druidDataSources) {
|
||||
druidDataSource.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,56 +4,27 @@ import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.alibaba.druid.pool.xa.DruidXADataSource;
|
||||
import com.atomikos.jdbc.AtomikosDataSourceBean;
|
||||
import com.ruoyi.common.utils.spring.SpringUtils;
|
||||
import com.ruoyi.framework.config.properties.DruidProperties;
|
||||
|
||||
@Configuration
|
||||
@DependsOn({ "transactionManager" })
|
||||
@ConfigurationProperties(prefix = "spring.datasource.dynamic")
|
||||
public class DynamicDataSourceProperties implements InitializingBean {
|
||||
private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceProperties.class);
|
||||
public class DynamicDataSourceProperties {
|
||||
|
||||
private Map<String, DataSourceProperties> datasource;
|
||||
private String primary;
|
||||
private Map<String, DataSource> targetDataSources = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
datasource.forEach((name, props) -> targetDataSources.put(name, createDataSource(name, props)));
|
||||
}
|
||||
|
||||
protected DataSource createDataSource(String name, DataSourceProperties dataSourceProperties) {
|
||||
Properties prop = build(dataSourceProperties);
|
||||
DruidXADataSource dataSource = new DruidXADataSource();
|
||||
dataSource.setConnectProperties(prop);
|
||||
setProperties(dataSource, prop);
|
||||
validateDataSource(dataSource);
|
||||
logger.info("数据源:{} 链接成功", name);
|
||||
AtomikosDataSourceBean ds = new AtomikosDataSourceBean();
|
||||
ds.setXaDataSourceClassName("com.alibaba.druid.pool.xa.DruidXADataSource");
|
||||
ds.setUniqueResourceName(name);
|
||||
ds.setXaProperties(prop);
|
||||
ds.setXaDataSource(dataSource);
|
||||
return ds;
|
||||
}
|
||||
|
||||
private void validateDataSource(DataSource dataSource) {
|
||||
public void validateDataSource(DataSource dataSource) {
|
||||
try (Connection conn = dataSource.getConnection()) {
|
||||
String validationQuery = "SELECT 1";
|
||||
try (Statement stmt = conn.createStatement();
|
||||
@ -143,12 +114,4 @@ public class DynamicDataSourceProperties implements InitializingBean {
|
||||
this.primary = primary;
|
||||
}
|
||||
|
||||
public Map<String, DataSource> getTargetDataSources() {
|
||||
return targetDataSources;
|
||||
}
|
||||
|
||||
public void setTargetDataSources(Map<String, DataSource> targetDataSources) {
|
||||
this.targetDataSources = targetDataSources;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,8 +11,8 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
import com.atomikos.util.IntraVmObjectRegistry;
|
||||
import com.ruoyi.common.service.mybatis.CreateSqlSessionFactory;
|
||||
import com.ruoyi.framework.datasource.DataSourceManagement;
|
||||
import com.ruoyi.framework.datasource.DynamicSqlSessionTemplate;
|
||||
|
||||
@Configuration
|
||||
@ -24,18 +24,16 @@ public class SqlSessionFactoryConfig {
|
||||
@Autowired
|
||||
DynamicDataSourceProperties dataSourceProperties;
|
||||
|
||||
@Autowired
|
||||
DataSourceManagement dataSourceManagement;
|
||||
|
||||
@Bean(name = "sqlSessionTemplate")
|
||||
public DynamicSqlSessionTemplate sqlSessionTemplate(Environment env) throws Exception {
|
||||
Map<Object, SqlSessionFactory> sqlSessionFactoryMap = new HashMap<>();
|
||||
Map<String, DataSource> targetDataSources = dataSourceProperties.getTargetDataSources();
|
||||
Map<String, DataSource> targetDataSources = dataSourceManagement.getDataSourcesMap();
|
||||
for (Map.Entry<String, DataSource> entry : targetDataSources.entrySet()) {
|
||||
SqlSessionFactory sessionFactory = createSqlSessionFactory.createSqlSessionFactory(env, entry.getValue());
|
||||
sqlSessionFactoryMap.put(entry.getKey(), sessionFactory);
|
||||
// 应对热重载的特殊处理
|
||||
Object ret = com.atomikos.icatch.config.Configuration.removeResource(entry.getKey());
|
||||
if (ret != null) {
|
||||
IntraVmObjectRegistry.removeResource(entry.getKey());
|
||||
}
|
||||
}
|
||||
SqlSessionFactory factoryMaster = sqlSessionFactoryMap.get(dataSourceProperties.getPrimary());
|
||||
if (factoryMaster == null) {
|
||||
|
@ -0,0 +1,60 @@
|
||||
package com.ruoyi.framework.datasource;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.ruoyi.common.service.datasource.CreateDataSource;
|
||||
import com.ruoyi.framework.config.DynamicDataSourceProperties;
|
||||
|
||||
@Component
|
||||
public class DataSourceManagement implements InitializingBean {
|
||||
private Map<String, DataSource> targetDataSources = new HashMap<>();
|
||||
|
||||
@Autowired
|
||||
private DynamicDataSourceProperties dataSourceProperties;
|
||||
|
||||
@Autowired
|
||||
private CreateDataSource c;
|
||||
|
||||
@Bean(name = "dynamicDataSource")
|
||||
@Primary
|
||||
public DynamicDataSource dataSource() {
|
||||
Map<Object, Object> objectMap = new HashMap<>();
|
||||
Map<String, DataSource> targetDataSources = this.getDataSourcesMap();
|
||||
for (Map.Entry<String, DataSource> entry : targetDataSources.entrySet()) {
|
||||
objectMap.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return new DynamicDataSource(targetDataSources.get(dataSourceProperties.getPrimary()), objectMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
dataSourceProperties.getDatasource()
|
||||
.forEach((name, props) -> this.putDataSource(name, c.createDataSource(name, props)));
|
||||
}
|
||||
|
||||
public DataSource getDataSource(String name) {
|
||||
return targetDataSources.get(name);
|
||||
}
|
||||
|
||||
public Collection<DataSource> getDataSources() {
|
||||
return targetDataSources.values();
|
||||
}
|
||||
|
||||
public Map<String, DataSource> getDataSourcesMap() {
|
||||
return targetDataSources;
|
||||
}
|
||||
|
||||
public void putDataSource(String name, DataSource dataSource) {
|
||||
targetDataSources.put(name, dataSource);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user