Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,27 @@
* @author TaoYu
*/
@Slf4j
@AllArgsConstructor
public class ConfigMergeCreator<C, T> {

private final String configName;

private final Class<C> configClazz;

private final Class<T> targetClazz;

/**
* Cached BeanInfo to avoid repeated introspection for better performance
*/
private volatile BeanInfo cachedBeanInfo;

public ConfigMergeCreator(String configName, Class<C> configClazz, Class<T> targetClazz) {
if (configName == null || configClazz == null || targetClazz == null) {
throw new IllegalArgumentException("ConfigMergeCreator parameters cannot be null");
}
this.configName = configName;
this.configClazz = configClazz;
this.targetClazz = targetClazz;
}

@SneakyThrows
@SuppressWarnings("unchecked")
Expand All @@ -51,8 +64,17 @@ public T create(C global, C item) {
return (T) item;
}
T result = targetClazz.getDeclaredConstructor().newInstance();
BeanInfo beanInfo = Introspector.getBeanInfo(configClazz, Object.class);
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();

// Use cached BeanInfo or create and cache it
if (cachedBeanInfo == null) {
synchronized (this) {
if (cachedBeanInfo == null) {
cachedBeanInfo = Introspector.getBeanInfo(configClazz, Object.class);
}
}
}

PropertyDescriptor[] propertyDescriptors = cachedBeanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : propertyDescriptors) {
Class<?> propertyType = pd.getPropertyType();
if (Properties.class == propertyType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,11 @@ public synchronized void addDataSource(String ds, DataSource dataSource) {
* @param dataSource 新数据源
*/
private void addGroupDataSource(String ds, DataSource dataSource) {
if (ds.contains(UNDERLINE)) {
String group = ds.split(UNDERLINE)[0];
int underlineIndex = ds.indexOf(UNDERLINE);
// Only process if underscore exists and is not at the start (group name must not be empty)
if (underlineIndex > 0) {
// Extract group name without using split() for better performance
String group = ds.substring(0, underlineIndex);
GroupDataSource groupDataSource = groupDataSources.get(group);
if (groupDataSource == null) {
try {
Expand Down Expand Up @@ -194,8 +197,11 @@ public synchronized void removeDataSource(String ds) {
}
if (dataSourceMap.containsKey(ds)) {
DataSource dataSource = dataSourceMap.remove(ds);
if (ds.contains(UNDERLINE)) {
String group = ds.split(UNDERLINE)[0];
int underlineIndex = ds.indexOf(UNDERLINE);
// Only process if underscore exists and is not at the start (group name must not be empty)
if (underlineIndex > 0) {
// Extract group name without using split() for better performance
String group = ds.substring(0, underlineIndex);
if (groupDataSources.containsKey(group)) {
DataSource oldDataSource = groupDataSources.get(group).removeDatasource(ds);
if (oldDataSource == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

Expand All @@ -39,6 +41,13 @@ public class GroupDataSource {
private DynamicDataSourceStrategy dynamicDataSourceStrategy;

private Map<String, DataSource> dataSourceMap = new ConcurrentHashMap<>();

/**
* Cached immutable list of datasource keys to avoid recreating ArrayList on every call.
* Marked as volatile to ensure visibility across threads.
* Immutable to prevent concurrent modification issues.
*/
private volatile List<String> cachedDsKeys = Collections.emptyList();

public GroupDataSource(String groupName, DynamicDataSourceStrategy dynamicDataSourceStrategy) {
this.groupName = groupName;
Expand All @@ -53,23 +62,35 @@ public GroupDataSource(String groupName, DynamicDataSourceStrategy dynamicDataSo
* @return the previous value associated with ds, or null if there was no mapping for ds.
*/
public DataSource addDatasource(String ds, DataSource dataSource) {
return dataSourceMap.put(ds, dataSource);
DataSource result = dataSourceMap.put(ds, dataSource);
// Update cached keys list after modification with immutable copy
// Note: Cache rebuild is acceptable here as add/remove operations are infrequent
// compared to determineDataSource calls which benefit from the cached list
cachedDsKeys = Collections.unmodifiableList(new ArrayList<>(dataSourceMap.keySet()));
return result;
}

/**
* @param ds the name of the datasource
*/
public DataSource removeDatasource(String ds) {
return dataSourceMap.remove(ds);
DataSource result = dataSourceMap.remove(ds);
// Update cached keys list after modification with immutable copy
// Note: Cache rebuild is acceptable here as add/remove operations are infrequent
// compared to determineDataSource calls which benefit from the cached list
cachedDsKeys = Collections.unmodifiableList(new ArrayList<>(dataSourceMap.keySet()));
return result;
}

/**
* determineDsKey
* Performance optimized: uses cached immutable list instead of creating new ArrayList on each call
*
* @return the name of the datasource
*/
public String determineDsKey() {
return dynamicDataSourceStrategy.determineKey(new ArrayList<>(dataSourceMap.keySet()));
// Safe to pass directly - list is immutable and strategies only read from it
return dynamicDataSourceStrategy.determineKey(cachedDsKeys);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ public class LoadBalanceDynamicDataSourceStrategy implements DynamicDataSourceSt

@Override
public String determineKey(List<String> dsNames) {
return dsNames.get(Math.abs(index.getAndAdd(1) % dsNames.size()));
// Use getAndIncrement with proper modulo to prevent issues with negative values
// when counter overflows. Using & Integer.MAX_VALUE ensures non-negative value
int currentIndex = index.getAndIncrement() & Integer.MAX_VALUE;
return dsNames.get(currentIndex % dsNames.size());
}
}