Java开发中一个项目连接多个数据源时,可能会有需要动态指定一个方法所使用的数据源的场景。例如不同的用户查询不同的数据源。
我遇到的需求是这样的:设计一个公共的数据字典组件,该组件需要连接数据源,使用方引入该组件后可以直接调用组件提供的服务方法。如果使用方有多个数据源,那么组件就不知道该使用哪个数据源了,使用方又不能修改组件的源码,因此需要通过配置来实现运行时指定数据源。
实现代码如下:
-
扩展mybatis plus的数据源处理类,使其支持Spring EL表达式。
import com.baomidou.dynamic.datasource.processor.DsProcessor; import org.aopalliance.intercept.MethodInvocation; import org.springframework.beans.factory.config.BeanExpressionContext; import org.springframework.beans.factory.config.BeanExpressionResolver; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.expression.StandardBeanExpressionResolver; public class DsSpelExpressionProcessor extends DsProcessor { private ConfigurableListableBeanFactory beanFactory; public DsSpelExpressionProcessor(ConfigurableListableBeanFactory beanFactory) { this.beanFactory = beanFactory; } @Override public boolean matches(String key) { return true; } @Override public String doDetermineDatasource(MethodInvocation invocation, String key) { BeanExpressionResolver resolver = beanFactory.getBeanExpressionResolver(); if (resolver == null) { resolver = new StandardBeanExpressionResolver(); } BeanExpressionContext expressionContext = new BeanExpressionContext(beanFactory, null); Object result = resolver.evaluate(key, expressionContext); return result.toString(); } }
-
配置类中声明这个Bean。
@Configuration public class DsConfiguration { @Autowired private ConfigurableListableBeanFactory beanFactory; @Bean @ConditionalOnMissingBean public DsProcessor dsProcessor() { DsHeaderProcessor headerProcessor = new DsHeaderProcessor(); DsSessionProcessor sessionProcessor = new DsSessionProcessor(); DsSpelExpressionProcessor spelExpressionProcessor = new DsSpelExpressionProcessor(beanFactory); headerProcessor.setNextProcessor(sessionProcessor); sessionProcessor.setNextProcessor(spelExpressionProcessor); return headerProcessor; } }
-
创建Spring Boot配置类,供使用方自定义组件的数据源。
@ConfigurationProperties(prefix = "jz.component.directory") @Component("jzCommonDirectoryConfigurationProperties") @Getter @Setter public class JzCommonDirectoryConfigurationProperties { /** 数据源名称,指定common_directory表所在数据源 */ private String datasourceName; }
-
在组件对外提供的接口上指定数据源。
@Service @DS("#{jzCommonDirectoryConfigurationProperties.datasourceName}") public class JzCommonDirectoryManagerImpl implements IJzCommonDirectoryManager { }
-
大功告成!
使用方引入该组件后,在
application.yml
配置文件中配置好数据源名称(对应mybatis plus多数据源配置的数据源名称),组件就可以正常工作了。jz: component: config: datasource-name: "biz"