多資料來源及事物在fast-family-master基礎框架中設計實踐指南
本篇給大家介紹如何設計開發多資料來源及多資料來源事物。
閱讀本篇文章涵蓋知識點如下:
1.註解反射
2.Spring Aop代理
3.ThreadLocal
4.XA事物管理
具體實現如下:
建立動態資料來源切換註解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSourceAnnotation {
String name() default "";
}
複製程式碼
使用aop代理DataSourceAnnotation註解進行資料來源切換
@Aspect
@Component
@Slf4j
@Order(1)
public class DynamicDataSourceAspect {
@Pointcut("@within(com.fast.family.datasource.annotation.DataSourceAnnotation) ||" +
" @annotation(com.fast.family.datasource.annotation.DataSourceAnnotation)")
public void pointcut() {
}
;
@Before("pointcut()")
public void before(JoinPoint joinPoint) {
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
DataSourceAnnotation dataSourceAnnotation =
method.getAnnotation(DataSourceAnnotation.class);
if (dataSourceAnnotation == null) {
dataSourceAnnotation = joinPoint.getTarget().getClass()
.getAnnotation(DataSourceAnnotation.class);
if (dataSourceAnnotation == null) {
return;
}
}
String dataSourceKey = dataSourceAnnotation.name();
if (dataSourceKey != null) {
DataSourceContextHolder.add(dataSourceKey);
}
}
public void after(JoinPoint joinPoint) {
DataSourceContextHolder.clear();
}
}
複製程式碼
建立動態資料來源介面
public interface DynamicDataSource {
Map<Object, Object> loadDataSource();
}
複製程式碼
載入配置檔案指定的資料來源資訊
@Component
@Slf4j
public class DefaultDynamicDataSouce implements DynamicDataSource {
@Autowired
private DynamicDataSourceProperties properties;
//載入配置的資料來源資訊進快取
@Override
public Map<Object, Object> loadDataSource() {
Class<? extends DataSource> type = properties.getType();
DataSource result = (DataSource) BeanUtils.instantiate(type);
Map<String, DynamicDataSourceProperties> map = properties.getDatasource();
Iterator<Map.Entry<String, DynamicDataSourceProperties>> iterator = map.entrySet().iterator();
Map<Object, Object> dataSourceMap = new HashMap<>();
while (iterator.hasNext()) {
Map.Entry<String, DynamicDataSourceProperties> entry = iterator.next();
DataSource dataSource = DynamicDataSourceFatcory.createDateSource(entry.getValue(), result);
dataSourceMap.put(entry.getKey(), dataSource);
DynamicDataSourceCacheUtils.put(entry.getKey(), dataSource);
}
return dataSourceMap;
}
}
複製程式碼
多資料來源Properties配置檔案
@Data
@ConfigurationProperties(prefix = "fast.family")
public class DynamicDataSourceProperties {
private Class<? extends DataSource> type;
private DruidDataSourceProperties druid;
private AtomikosDataSouceProperties atomikos = new AtomikosDataSouceProperties();
private Map<String, DynamicDataSourceProperties> datasource = new HashMap<>();
}
複製程式碼
繼承AbstractRoutingDataSource來進行資料來源切換
@Slf4j
public class DynamicRoutingDataSource extends AbstractRoutingDataSource
implements InitializingBean {
@Autowired
private DynamicDataSourceProperties properties;
@Autowired
private DynamicDataSource dynamicDataSource;
@Override
protected DataSource determineTargetDataSource() {
String dataSourceKey = DataSourceContextHolder.get();
//根據DataSourceAnnotation指定資料來源名稱來切換資料來源
//預設使用master資料來源
if (dataSourceKey != null && !dataSourceKey.equals("")) {
return DynamicDataSourceCacheUtils.get(dataSourceKey);
} else {
return DynamicDataSourceCacheUtils.get("master");
}
}
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.get();
}
@Override
public void afterPropertiesSet() {
this.setTargetDataSources(dynamicDataSource.loadDataSource());
}
}
複製程式碼
丟進spring 容器
@Configuration
@ConditionalOnClass(DynamicDataSourceProperties.class)
@EnableConfigurationProperties({DynamicDataSourceProperties.class})
public class DynamicDataSourceAutoConfigure {
@Bean
public DynamicRoutingDataSource routingDataSource() {
return new DynamicRoutingDataSource();
}
}
複製程式碼
疑問:
上述程式碼已經實現了基本的資料來源切換,那麼大家可能會有一個疑問就是,多資料來源及事物,這個事物是在哪裡管理呢? 這個時候就需要引入XA事物了。
其實奧祕就在DynamicDataSourceProperties中的type屬性,以阿里druid資料來源為例。
fast:
family:
type: com.alibaba.druid.pool.xa.DruidXADataSource #指定DruidXADataSource則帶有分散式XA事物管理,指定DruidDataSource則不具備分散式XA事物管理
datasource:
master:
druid:
username: root
password: root
url: jdbc:mysql://localhost:3306/master-db?useUnicode=true&characterEncoding=utf8
driverClassName: com.mysql.jdbc.Driver
atomikos:
uniqueResourceName: master-db
slave_0:
druid:
username: root
password: root
url: jdbc:mysql://localhost:3306/slave-db?useUnicode=true&characterEncoding=utf8
driverClassName: com.mysql.jdbc.Driver
atomikos:
uniqueResourceName: slave-db
複製程式碼
最後各位讀者覺得本篇文章對您有所幫助,可以點贊一波。
如對fast-family-master基礎框架感興趣可以star一波,地址如下:
https://github.com/fast-family/fast-family-master