Boosting Dubbo Performance with Spring Boot Auto‑Configuration and a Multi‑Data‑Source SDK
The article details how a high‑frequency Dubbo call bottleneck was resolved by creating a conditional Spring Boot auto‑configuration multi‑data‑source SDK that dynamically loads beans, avoids bean conflicts, and enables direct database access, dramatically reducing latency and system load.
Problem: Dubbo performance bottleneck
In a large micro‑service project, high‑frequency data‑query operations were invoked via Dubbo. Under high concurrency the latency became noticeable, and the Dubbo service could not be horizontally scaled because of database constraints.
Solution: Conditional auto‑configuration multi‑data‑source SDK
Project structure
sdk-multi-datasource/
├── src/main/java/com/example/sdk/
│ ├── config/
│ │ ├── condition/AnySdkDataSourceCondition.java
│ │ ├── datasource/SdkPrimaryDataConfig.java
│ │ ├── datasource/SdkSecondaryDataConfig.java
│ │ └── SdkAutoConfiguration.java
│ ├── dao/primary/SdkAppInfoDao.java
│ ├── dao/secondary/SdkOtherDataDao.java
│ ├── service/SdkAppInfoService.java
│ ├── service/SdkOtherDataService.java
│ └── ...
├── src/main/resources/META-INF/spring.factories
└── pom.xmlConditional class: detecting data‑source configuration
public class AnySdkDataSourceCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment env = context.getEnvironment();
return env.containsProperty("spring.datasource.sdk-primary.jdbc-url") ||
env.containsProperty("spring.datasource.sdk-secondary.jdbc-url");
}
}Primary data‑source configuration
@Configuration
@ConditionalOnProperty(prefix = "spring.datasource.sdk-primary", name = "jdbc-url")
@MapperScan(basePackages = "com.example.sdk.dao.primary", sqlSessionFactoryRef = "sdkPrimarySqlSessionFactory")
public class SdkPrimaryDataConfig {
@Bean(name = "sdkPrimaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.sdk-primary")
public DataSource sdkPrimaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "sdkPrimarySqlSessionFactory")
public SqlSessionFactory sdkPrimarySqlSessionFactory(@Qualifier("sdkPrimaryDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath*:mapper/primary/*.xml"));
return bean.getObject();
}
@Bean(name = "sdkPrimarySqlSessionTemplate")
public SqlSessionTemplate sdkPrimarySqlSessionTemplate(@Qualifier("sdkPrimarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
@Bean(name = "sdkPrimaryTransactionManager")
public DataSourceTransactionManager sdkPrimaryTransactionManager(@Qualifier("sdkPrimaryDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}Secondary data‑source configuration
The secondary configuration mirrors the primary one, with bean names, package paths, and property prefixes changed from primary to secondary.
DAO layer interfaces
@Mapper
public interface SdkAppInfoDao {
AppInfo getByBusinessId(String businessId);
}Service layer implementation
public class SdkAppInfoService {
private SdkAppInfoDao sdkAppInfoDao;
public void setSdkAppInfoDao(SdkAppInfoDao dao) { this.sdkAppInfoDao = dao; }
public AppInfo getByBusinessId(String businessId) {
return sdkAppInfoDao.getByBusinessId(businessId);
}
}Auto‑configuration class
@Configuration
@Conditional(AnySdkDataSourceCondition.class)
@Import({SdkPrimaryDataConfig.class, SdkSecondaryDataConfig.class})
public class SdkAutoConfiguration {
@Bean @Lazy @ConditionalOnProperty(prefix = "spring.datasource.sdk-primary", name = "jdbc-url")
public SdkAppInfoService sdkAppInfoService(SdkAppInfoDao dao) {
SdkAppInfoService service = new SdkAppInfoService();
service.setSdkAppInfoDao(dao);
return service;
}
@Bean @Lazy @ConditionalOnProperty(prefix = "spring.datasource.sdk-secondary", name = "jdbc-url")
public SdkOtherDataService sdkOtherDataService(SdkOtherDataDao dao) {
SdkOtherDataService service = new SdkOtherDataService();
service.setSdkOtherDataDao(dao);
return service;
}
}Registration in spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.sdk.config.SdkAutoConfigurationConsumer usage
Add the SDK as a Maven dependency and configure the desired data sources following Spring Boot conventions.
<dependency>
<groupId>com.example</groupId>
<artifactId>sdk-multi-datasource</artifactId>
<version>1.0.0</version>
</dependency> spring:
datasource:
sdk-primary:
jdbc-url: jdbc:mysql://primary-db-host:3306/primary_db
username: db_user
password: db_password
driver-class-name: com.mysql.jdbc.Driver
sdk-secondary:
jdbc-url: jdbc:mysql://secondary-db-host:3306/secondary_db
username: db_user
password: db_password
driver-class-name: com.mysql.jdbc.DriverInject the SDK service directly in a controller.
@RestController
public class BusinessController {
@Autowired
private SdkAppInfoService sdkAppInfoService;
@GetMapping("/app-info/{businessId}")
public AppInfo getAppInfo(@PathVariable String businessId) {
return sdkAppInfoService.getByBusinessId(businessId);
}
}Result and analysis
Replacing high‑frequency Dubbo calls with local database connections via the SDK significantly lowered latency and system load. The conditional annotations ensure that beans are created only when the corresponding data source is configured, preventing unnecessary bean loading, memory waste, and runtime errors.
On‑demand loading : Beans are instantiated only after the related data source property is present.
Conflict avoidance : All SDK beans are prefixed with "Sdk", eliminating name clashes with existing beans.
Flexible configuration : Teams can enable any combination of primary and secondary data sources.
@Lazy effect : Service beans are lazily initialized, guaranteeing that their DAO dependencies are already available when the service is first used.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
