实现MongoDB多数据源的自动切换
来源:互联网 发布:android 打开淘宝链接 编辑:程序博客网 时间:2024/06/05 15:23
实现MongoDB多数据源的自动切换
一、实现原理
1、通过参考Spring的AbstractRoutingDataSource抽象类(该类充当了DataSource的路由中介, 能有在运行时, 根据某种key值来动态切换到真正的DataSource上),重新构造一个AbstractMongoDBRoutingMongoTemplate抽象类,实现多mongdbTemplate的自动切换。
AbstractMongoDBRoutingMongoTemplate的源码:
/** * @title: AbstractMongoDBRoutingMongoTemplate * @company: 北京云知声信息技术有限公司 * @author: lizehao * @date: 2016年10月18日 */public abstract class AbstractMongoDBRoutingMongoTemplate implements InitializingBean { private Map<Object, Object> targetMongoTemplates; private Object defaultTargetMongoTemplate; private Map<Object, MongoTemplate> resolvedMongoTemplates; private MongoTemplate resolvedDefaultMongoTemplate; public void setTargetMongoTemplates(Map<Object, Object> targetMongoTemplates) { this.targetMongoTemplates = targetMongoTemplates; } @Override public void afterPropertiesSet() { if (this.targetMongoTemplates == null) { throw new IllegalArgumentException("Property 'targetMongoTemplates' is required"); } this.resolvedMongoTemplates = new HashMap<Object, MongoTemplate>(this.targetMongoTemplates.size()); for (Map.Entry<Object, Object> entry : this.targetMongoTemplates.entrySet()) { Object lookupKey = resolveSpecifiedLookupKey(entry.getKey()); MongoTemplate mongoTemplate = resolveSpecifiedMongoTemplate(entry.getValue()); this.resolvedMongoTemplates.put(lookupKey, mongoTemplate); } if (this.defaultTargetMongoTemplate != null) { this.resolvedDefaultMongoTemplate = resolveSpecifiedMongoTemplate(this.defaultTargetMongoTemplate); } } protected Object resolveSpecifiedLookupKey(Object lookupKey) { return lookupKey; } protected MongoTemplate resolveSpecifiedMongoTemplate(Object mongoTemplate) throws IllegalArgumentException { if (mongoTemplate instanceof MongoTemplate) { return (MongoTemplate) mongoTemplate; } else { throw new IllegalArgumentException( "Illegal data source value - only [org.springframework.data.mongodb.core.MongoTemplate] and String supported: " + mongoTemplate); } } protected MongoTemplate determineMongoTemplate() { Assert.notNull(this.resolvedMongoTemplates, "mongoTemplate router not initialized"); Object lookupKey = determineCurrentLookupKey(); MongoTemplate mongoTemplate = this.resolvedMongoTemplates.get(lookupKey); if (mongoTemplate == null && (lookupKey == null)) { mongoTemplate = this.resolvedDefaultMongoTemplate; } if (mongoTemplate == null) { throw new IllegalStateException("Cannot determine target MongoTemplate for lookup key [" + lookupKey + "]"); } return mongoTemplate; } protected abstract Object determineCurrentLookupKey();}
重点是determineMongoTemplate()方法,看代码:
这段源码的重点在于determineCurrentLookupKey()方法,这是AbstractMongoDBRoutingMongoTemplate 类中的一个抽象方法,而它的返回值是你所要用的MongoTemplate的key值,有了这个key值,resolvedMongoTemplates(这是个map,由配置文件中设置好后存入的)就从中取出对应的MongoTemplate,如果找不到,就用配置默认的数据源。
看完代码,应该有点启发了吧,没错!你要扩展AbstractMongoDBRoutingMongoTemplate类,并重写其中的determineCurrentLookupKey()方法,来实现MongoTemplate的切换:
/** * @title: MongoDBJdbcTemplate * @company: 北京云知声信息技术有限公司 * @author: lizehao * @date: 2016年10月18日 */public class MongoDBTemplate extends AbstractMongoDBRoutingMongoTemplate { public MongoDBTemplate() { } public MongoTemplate getMongoTemplate() { return determineMongoTemplate(); } @Override protected Object determineCurrentLookupKey() { return MongodbTemplateContextHolder.getMongoDBTemplate(); }}
mongodbTemplateContextHolder这个类则是我们自己封装的对数据源进行操作的类:
/** * @title: mongodbTemplateContextHolder * @company: 北京云知声信息技术有限公司 * @author: lizehao * @date: 2016年10月18日 */public class MongodbTemplateContextHolder{ private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(); public static void setMongoDBTemplate(String mongodbTemplateType) { contextHolder.set(mongodbTemplateType); } public static String getMongoDBTemplate() { return contextHolder.get(); } public static void clearMongoDBTemplate() { contextHolder.remove(); }}
定义mongodbTemplate类型 使用的枚举
/** * @title: mongoDB数据源类型 * @company: 北京云知声信息技术有限公司 * @author: lizehao * @date: 2016年10月18日 */public enum MongoDBDataSource { USER_CENTER("uc"), // 用户中心数据 DEVICE_CENTER("device"); // 设备中心数据 private final String value; // 构造器默认也只能是private, 从而保证构造函数只能在内部使用 private MongoDBDataSource(String value) { this.value = value; } public String getValue() { return value; }}
2、有人就要问,那你setMongoDBTemplate这方法是要在什么时候执行呢?当然是在你需要切换mongodbTemplate的时候执行啦。手动在代码中调用写死吗?这是多蠢的方法,当然要让它动态咯。所以我们可以应用spring aop来设置,在dao层中需要切换mongodbTemplate的方法上:
/** * @title: 多数据源动态切换 * @company: 北京云知声信息技术有限公司 * @author: lizehao * @date: 2016年8月25日 */@Aspect@Componentpublic class DynamicMongoDBDataSourceAspect { private static final String PREFIX = ".dao.mongo."; @Pointcut("execution(* com.unisound.iot.busi.web.dao.mongo..*.*(..))") private void daoMethod() { // do nothing } @Before("daoMethod()") public void before(JoinPoint joinPoint) { Signature signature = joinPoint.getSignature(); for (MongoDBDataSource mongoDBDataSource : MongoDBDataSource.values()) { if (signature.getDeclaringTypeName().indexOf(PREFIX + mongoDBDataSource.getValue()) > -1) { JdbcTemplateContextHolder.setJdbcTemplate(mongoDBDataSource.getValue()); break; } } }}
二、配置文件
为了精简篇幅,省略了无关本内容主题的配置。spring-mongodb.xml
<!-- mongo多数据源切换 --> <bean id="mongoDBTemplate" class="com.unisound.iot.busi.web.common.dataSource.mongodbTemplate.MongoDBTemplate"> <property name="targetMongoTemplates"> <map key-type="java.lang.String"> <entry key="device" value-ref="deviceMongoTemplate"></entry> </map> </property> </bean> <!-- MongoDB相关配置 --> <mongo:mongo-client id="mongo" replica-set="${mongo.replicaSet}" credentials="${mongo.username}:${mongo.password}@${mongo.dbname}"> <mongo:client-options max-wait-time="${mongo.maxWaitTime}" socket-timeout="${mongo.socketTimeout}" connect-timeout="${mongo.connectTimeout}" socket-keep-alive="${mongo.socketKeepAlive}" connections-per-host="${mongo.connectionsPerHost}" threads-allowed-to-block-for-connection-multiplier="${mongo.threadsAllowedToBlockForConnectionMultiplier}" /> </mongo:mongo-client> <bean id="mongoDbFactory" class="org.springframework.data.mongodb.core.SimpleMongoDbFactory"> <constructor-arg ref="mongo" /> <constructor-arg value="${mongo.dbname}" /> </bean> <!-- 去掉MongoDB数据中的_class属性的方法 --> <bean id="mappingContext" class="org.springframework.data.mongodb.core.mapping.MongoMappingContext" /> <bean id="defaultMongoTypeMapper" class="org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper"> <constructor-arg name="typeKey"> <null /> </constructor-arg> </bean> <bean id="mappingMongoConverter" class="org.springframework.data.mongodb.core.convert.MappingMongoConverter"> <constructor-arg name="mongoDbFactory" ref="mongoDbFactory" /> <constructor-arg name="mappingContext" ref="mappingContext" /> <property name="typeMapper" ref="defaultMongoTypeMapper" /> </bean> <bean id="deviceMongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> <constructor-arg name="mongoDbFactory" ref="mongoDbFactory" /> <constructor-arg name="mongoConverter" ref="mappingMongoConverter" /> </bean>
- 实现MongoDB多数据源的自动切换
- 【Spring】使用Spring的AbstractRoutingDataSource实现多数据源切换
- 使用Spring的AbstractRoutingDataSource实现多数据源切换
- 【Spring】使用Spring的AbstractRoutingDataSource实现多数据源切换
- hibernate4+spring实现多数据源切换
- Spring实现多数据源动态切换
- Spring Boot配置多数据源并实现Druid自动切换
- 多数据源切换
- Spring多数据源的动态切换
- Spring多数据源的动态切换
- 多数据源之间的切换
- spring的AbstractRoutingDataSource 多数据源切换
- springboot整合mybatis实现多数据库的切换
- 多数据源的实现
- java 通过继承类AbstractRoutingDataSource 而实现的 多数据源切换 的 缺陷(二)
- 初尝Spring AOP --实现多数据源切换
- springMvc-Mybatis 实现主从数据库/多数据源切换配置
- JFinal 多数据源切换,实现数据迁移
- 使用JdbcTemplate模板时传递的参数Map和Object []数组
- Out of Memory,Matlab
- Python下调用json.dumps中文显示问题及解决办法
- angular之页面跳转隐藏tab
- 深入理解HashMap
- 实现MongoDB多数据源的自动切换
- hdoj-【2136 Largest prime factor】
- Docker系列~代码放在Docker里面还是外面?(八)
- surfview 的一般使用
- vs2012,如何调试dll工程
- python的excel操作
- FlushedInputStream:Android下InputStream发生网络中断时的解决办法
- 安卓 四种控制键盘的方法
- css其他样式