{"record":{"id":"526c78bbdd9968b5","repo":"hs-web/hsweb-framework","slug":"datasourceservice-not-ready","errorCode":null,"errorMessage":"dataSourceService not ready","messagePattern":"dataSourceService not ready","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/DataSourceHolder.java","lineNumber":30,"sourceCode":" */\npublic final class DataSourceHolder {\n\n\n    /**\n     * 动态数据源服务\n     */\n    static volatile DynamicDataSourceService dynamicDataSourceService;\n\n    static volatile JdbcSwitcher jdbcSwitcher = new DefaultJdbcSwitcher();\n    static volatile R2dbcSwitcher r2dbcSwitcher = new DefaultR2dbcSwicher();\n\n    public static boolean isDynamicDataSourceReady() {\n        return dynamicDataSourceService != null;\n    }\n\n    public static void checkDynamicDataSourceReady() {\n        if (dynamicDataSourceService == null) {\n            throw new UnsupportedOperationException(\"dataSourceService not ready\");\n        }\n    }\n\n    /**\n     * @return 动态数据源切换器\n     */\n    public static JdbcSwitcher switcher() {\n        return jdbcSwitcher;\n    }\n\n    public static R2dbcSwitcher r2dbcSwitcher() {\n        return r2dbcSwitcher;\n    }\n\n    /**\n     * @return 默认数据源\n     */\n    public static JdbcDataSource defaultDataSource() {","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/hs-web/hsweb-framework/blob/b2cfc85a57c70bf5b5cf6e7edae2d37102652ec8/hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/DataSourceHolder.java#L12-L48","documentation":"DataSourceHolder.checkDynamicDataSourceReady() throws UnsupportedOperationException when the static dynamicDataSourceService reference is still null, i.e. the dynamic datasource service bean was never injected into the holder.","triggerScenarios":"Calling DataSourceHolder.switcher().datasource()/existing()/defaultDataSource (which call the check) in a context where the AopDataSourceSwitcherAutoConfiguration/DataSourceService was not initialized, or before Spring finished wiring the bean.","commonSituations":"Running code outside the Spring context (unit tests, static initializers); using the datasource API in a module without hsweb-datasource on the classpath/scan; calling switcher very early during startup before the service bean is created.","solutions":["Ensure the application includes hsweb-datasource-api/auto-configuration and the dynamic datasource service bean is registered","Call the datasource API only from Spring-managed, post-startup code","Check isDynamicDataSourceReady() before calling and fail gracefully","In tests, initialize the holder manually or mock the service"],"exampleFix":"// before\nDataSourceHolder.switcher().datasource().use(\"ds1\");\n// after\nif (DataSourceHolder.isDynamicDataSourceReady()) {\n    DataSourceHolder.switcher().datasource().use(\"ds1\");\n} else {\n    throw new IllegalStateException(\"dynamic datasource service not initialized\");\n}","handlingStrategy":"type-guard","validationCode":"if (!DataSourceHolder.isDynamicDataSourceReady()) {\n    throw new IllegalStateException(\"dynamic datasource service not initialized\");\n}","typeGuard":"static boolean canSwitch() {\n    return DataSourceHolder.isDynamicDataSourceReady();\n}","tryCatchPattern":"try {\n    DataSourceHolder.switcher().datasource().use(id);\n} catch (UnsupportedOperationException e) {\n    if (e.getMessage().contains(\"not ready\")) {\n        log.error(\"datasource service missing; using plain JDBC\");\n    } else throw e;\n}","preventionTips":["Include and scan the datasource auto-configuration in the app","Only call the holder after Spring context startup completes","Guard test code: initialize or mock the holder","Prefer injecting DataSourceService directly over static access"],"tags":["datasource","initialization","spring"],"backgroundTag":"missing-dependency","analyzedSha":"b2cfc85a57c70bf5b5cf6e7edae2d37102652ec8","analyzedAt":"2026-09-13T09:05:02.172Z","contentChangedAt":"2026-09-13T09:05:02.172Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}