SpringBoot配置数据库密码加密的实现
你在使用MyBatis的过程中,是否有想过多个数据源应该如何配置,如何去实现?出于这个好奇心,我在DruidWiki的数据库多数据源中知晓Spring提供了对多数据源的支持,基于Spring提供的AbstractRoutingDataSource,可以自己实现数据源的切换。
一、配置动态数据源
下面就如何配置动态数据源提供一个简单的实现:
org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource,代码如下:
publicabstractclassAbstractRoutingDataSourceextendsAbstractDataSourceimplementsInitializingBean{ @Nullable privateObjectdefaultTargetDataSource; @Nullable privateMap
重写AbstractRoutingDataSource的determineCurrentLookupKey()方法,可以实现对多数据源的支持
思路:
- 重写其determineCurrentLookupKey()方法,支持选择不同的数据源
- 初始化多个DataSource数据源到AbstractRoutingDataSource的resolvedDataSources属性中
- 然后通过SpringAOP,以自定义注解作为切点,根据不同的数据源的Key值,设置当前线程使用的数据源
接下来的实现方式是SpringBoot结合Druid配置动态数据源
(一)引入依赖
基于3.继承SpringBoot中已添加的依赖再添加对AOP支持的依赖,如下:
org.springframework.boot spring-boot-starter-aop
(二)开始实现
1.DataSourceContextHolder
DataSourceContextHolder使用ThreadLocal存储当前线程指定的数据源的Key值,代码如下:
packagecn.tzh.mybatis.config; importlombok.extern.slf4j.Slf4j; importjava.util.HashSet; importjava.util.Set; /** *@authortzh *@date2021/1/411:42 */ @Slf4j publicclassDataSourceContextHolder{ /** *线程本地变量 */ privatestaticfinalThreadLocalDATASOURCE_KEY=newThreadLocal<>(); /** *配置的所有数据源的Key值 */ publicstaticSet
2.MultipleDataSource
重写其AbstractRoutingDataSource的determineCurrentLookupKey()方法,代码如下:
packagecn.tzh.mybatis.config; importorg.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; /** *@authortzh *@date2021/1/411:44 */ publicclassMultipleDataSourceextendsAbstractRoutingDataSource{ /** *返回当前线程是有的数据源的Key * *@returndataSourceKey */ @Override protectedObjectdetermineCurrentLookupKey(){ returnDataSourceContextHolder.getDataSourceKey(); } }
3.DataSourceAspect切面
使用SpringAOP功能,定义一个切面,用于设置当前需要使用的数据源,代码如下:
packagecn.tzh.mybatis.config; importlombok.extern.log4j.Log4j2; importorg.aspectj.lang.JoinPoint; importorg.aspectj.lang.annotation.After; importorg.aspectj.lang.annotation.Aspect; importorg.aspectj.lang.annotation.Before; importorg.aspectj.lang.reflect.MethodSignature; importorg.springframework.stereotype.Component; importjava.lang.reflect.Method; /** *@authortzh *@date2021/1/411:46 */ @Aspect @Component @Log4j2 publicclassDataSourceAspect{ @Before("@annotation(cn.tzh.mybatis.config.TargetDataSource)") publicvoidbefore(JoinPointjoinPoint){ MethodSignaturemethodSignature=(MethodSignature)joinPoint.getSignature(); Methodmethod=methodSignature.getMethod(); if(method.isAnnotationPresent(TargetDataSource.class)){ TargetDataSourcetargetDataSource=method.getAnnotation(TargetDataSource.class); DataSourceContextHolder.setDataSourceKey(targetDataSource.value()); log.info("setthedatasourceofthecurrentthreadto[{}]",targetDataSource.value()); }elseif(joinPoint.getTarget().getClass().isAnnotationPresent(TargetDataSource.class)){ TargetDataSourcetargetDataSource=joinPoint.getTarget().getClass().getAnnotation(TargetDataSource.class); DataSourceContextHolder.setDataSourceKey(targetDataSource.value()); log.info("setthedatasourceofthecurrentthreadto[{}]",targetDataSource.value()); } } @After("@annotation(cn.tzh.mybatis.config.TargetDataSource)") publicvoidafter(){ DataSourceContextHolder.clear(); log.info("clearthedatasourceofthecurrentthread"); } }
4.DruidConfig
Druid配置类,代码如下:
packagecn.tzh.mybatis.config; importcom.alibaba.druid.support.spring.stat.DruidStatInterceptor; importorg.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator; importorg.springframework.context.annotation.Bean; importorg.springframework.context.annotation.Configuration; /** *@authortzh *@date2021/1/411:49 */ @Configuration publicclassDruidConfig{ @Bean(value="druid-stat-interceptor") publicDruidStatInterceptordruidStatInterceptor(){ returnnewDruidStatInterceptor(); } @Bean publicBeanNameAutoProxyCreatorbeanNameAutoProxyCreator(){ BeanNameAutoProxyCreatorbeanNameAutoProxyCreator=newBeanNameAutoProxyCreator(); beanNameAutoProxyCreator.setProxyTargetClass(true); //设置要监控的bean的id beanNameAutoProxyCreator.setInterceptorNames("druid-stat-interceptor"); returnbeanNameAutoProxyCreator; } }
5.MultipleDataSourceConfig
MyBatis的配置类,配置了2个数据源,代码如下:
packagecn.tzh.mybatis.config; importcom.alibaba.druid.pool.DruidDataSource; importcom.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; importorg.apache.ibatis.mapping.DatabaseIdProvider; importorg.apache.ibatis.plugin.Interceptor; importorg.apache.ibatis.scripting.LanguageDriver; importorg.apache.ibatis.session.ExecutorType; importorg.apache.ibatis.session.SqlSessionFactory; importorg.apache.ibatis.type.TypeHandler; importorg.mybatis.spring.SqlSessionFactoryBean; importorg.mybatis.spring.SqlSessionTemplate; importorg.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer; importorg.mybatis.spring.boot.autoconfigure.MybatisProperties; importorg.mybatis.spring.boot.autoconfigure.SpringBootVFS; importorg.springframework.beans.BeanWrapperImpl; importorg.springframework.beans.factory.ObjectProvider; importorg.springframework.boot.context.properties.ConfigurationProperties; importorg.springframework.boot.context.properties.EnableConfigurationProperties; importorg.springframework.context.annotation.Bean; importorg.springframework.context.annotation.Configuration; importorg.springframework.core.io.ResourceLoader; importorg.springframework.jdbc.datasource.DataSourceTransactionManager; importorg.springframework.transaction.PlatformTransactionManager; importorg.springframework.util.CollectionUtils; importorg.springframework.util.ObjectUtils; importorg.springframework.util.StringUtils; importjavax.sql.DataSource; importjava.beans.FeatureDescriptor; importjava.util.*; importjava.util.stream.Collectors; importjava.util.stream.Stream; /** *@authortzh *@projectNamecode-demo *@titleMultipleDataSourceConfig *@description *@date2021/1/413:43 */ @Configuration @EnableConfigurationProperties({MybatisProperties.class}) publicclassMultipleDataSourceConfig{ privatefinalMybatisPropertiesproperties; privatefinalInterceptor[]interceptors; privatefinalTypeHandler[]typeHandlers; privatefinalLanguageDriver[]languageDrivers; privatefinalResourceLoaderresourceLoader; privatefinalDatabaseIdProviderdatabaseIdProvider; privatefinalListconfigurationCustomizers; publicMultipleDataSourceConfig(MybatisPropertiesproperties,ObjectProvider interceptorsProvider,ObjectProvider typeHandlersProvider,ObjectProvider languageDriversProvider,ResourceLoaderresourceLoader,ObjectProvider databaseIdProvider,ObjectProvider >configurationCustomizersProvider){ this.properties=properties; this.interceptors=(Interceptor[])interceptorsProvider.getIfAvailable(); this.typeHandlers=(TypeHandler[])typeHandlersProvider.getIfAvailable(); this.languageDrivers=(LanguageDriver[])languageDriversProvider.getIfAvailable(); this.resourceLoader=resourceLoader; this.databaseIdProvider=(DatabaseIdProvider)databaseIdProvider.getIfAvailable(); this.configurationCustomizers=(List)configurationCustomizersProvider.getIfAvailable(); } @Bean(name="master",initMethod="init",destroyMethod="close") @ConfigurationProperties(prefix="spring.datasource.druid.master") publicDruidDataSourcemaster(){ returnDruidDataSourceBuilder.create().build(); } @Bean(name="slave",initMethod="init",destroyMethod="close") @ConfigurationProperties(prefix="spring.datasource.druid.slave") publicDruidDataSourceslave(){ returnDruidDataSourceBuilder.create().build(); } @Bean(name="dynamicDataSource") publicDataSourcedynamicDataSource(){ MultipleDataSourcedynamicRoutingDataSource=newMultipleDataSource(); Map
6.添加配置
server: port:9092 servlet: context-path:/mybatis-springboot-demo tomcat: accept-count:200 min-spare-threads:200 spring: application: name:mybatis-springboot-demo profiles: active:test servlet: multipart: max-file-size:100MB max-request-size:100MB datasource: type:com.alibaba.druid.pool.DruidDataSource druid: master: driver-class-name:com.mysql.cj.jdbc.Driver url:jdbc:mysql://127.0.0.1:3306/mybatis-demo username:root password:root initial-size:5#初始化时建立物理连接的个数 min-idle:20#最小连接池数量 max-active:20#最大连接池数量 slave: driver-class-name:com.mysql.cj.jdbc.Driver url:jdbc:mysql://127.0.0.1:3306/mybatis-demo1 username:root password:root initial-size:5#初始化时建立物理连接的个数 min-idle:20#最小连接池数量 max-active:20#最大连接池数量 mybatis: type-aliases-package:cn.tzh.mybatis.entity mapper-locations:classpath:cn/tzh/mybatis/mapper/*.xml config-location:classpath:mybatis-config.xml pagehelper: helper-dialect:mysql reasonable:true#分页合理化参数 offset-as-page-num:true#将RowBounds中的offset参数当成pageNum使用 supportMethodsArguments:true#支持通过Mapper接口参数来传递分页参数
其中分别定义了master和slave数据源的相关配置
这样一来,在DataSourceAspect切面中根据自定义注解,设置DataSourceContextHolder当前线程所使用的数据源的Key值,MultipleDataSource动态数据源则会根据该值设置需要使用的数据源,完成了动态数据源的切换
7.使用示例
在Mapper接口上面添加自定义注解@TargetDataSource,如下:
packagecn.tzh.mybatis.mapper; importcn.tzh.mybatis.config.TargetDataSource; importcn.tzh.mybatis.entity.User; importorg.apache.ibatis.annotations.Mapper; importorg.apache.ibatis.annotations.Param; /** *@authortzh *@date2020/12/2814:29 */ @Mapper publicinterfaceUserMapper{ UserselectUserOne(@Param("id")Longid); @TargetDataSource("slave") UserselectUserTwo(@Param("id")Longid); }
总结
上面就如何配置动态数据源的实现方式仅提供一种思路,其中关于多事务方面并没有实现,采用Spring提供的事务管理器,如果同一个方法中使用了多个数据源,并不支持多事务的,需要自己去实现(笔者能力有限),可以整合JAT组件,参考:SpringBoot2整合JTA组件多数据源事务管理
分布式事务解决方案推荐使用Seata分布式服务框架
到此这篇关于SpringBoot配置数据库密码加密的实现的文章就介绍到这了,更多相关SpringBoot数据库密码加密内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。