<context:component-scan base-package="com.snailteam.crawler" scoped-proxy="targetClass" /> <bean id="crawlerDataSource1" parent="parentDataSource"> <property name="driverClassName" value="${crawler.jdbc.driver}" /> <property name="url" value="${crawler.jdbc.url}" /> <property name="username" value="${crawler.jdbc.username}" /> <property name="password" value="${crawler.jdbc.password}" /> <property name="connectionProperties" value="autoReconnect=true;roundRobinLoadBalance=true" /> <property name="interName" value="1" /> </bean> <bean id="crawlerDataSource2" parent="parentDataSource"> <property name="driverClassName" value="${crawler.jdbc.driver}" /> <property name="url" value="${crawler.jdbc.url}" /> <property name="username" value="${crawler.jdbc.username}" /> <property name="password" value="${crawler.jdbc.password}" /> <property name="connectionProperties" value="autoReconnect=true;roundRobinLoadBalance=true" /> <property name="interName" value="2" /> </bean> <bean id="crawlerDataSource3" parent="parentDataSource"> <property name="driverClassName" value="${crawler.jdbc.driver}" /> <property name="url" value="${crawler.jdbc.url}" /> <property name="username" value="${crawler.jdbc.username}" /> <property name="password" value="${crawler.jdbc.password}" /> <property name="connectionProperties" value="autoReconnect=true;roundRobinLoadBalance=true" /> <property name="interName" value="3" /> </bean> <bean id="dynamicDataSource" class="org.springframework.jdbc.datasource.DynamicDataSource"> <property name="targetDataSources"> <map key-type="java.lang.String"> <entry key="1" value-ref="crawlerDataSource1" /> <entry key="2" value-ref="crawlerDataSource2" /> <entry key="3" value-ref="crawlerDataSource3" /> </map> </property> <property name="defaultTargetDataSource" ref="crawlerDataSource1"></property> </bean> <bean id="crawlerSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="configLocation" value="classpath:mybatis-configuration.xml" /> <property name="dataSource" ref="dynamicDataSource" /> <property name="plugins"> <list> <bean class="com.snailteam.core.plugins.ShardDBRouterPlugin"> <description>主辅数据库路由插件</description> </bean> <bean class="com.snailteam.core.plugins.TableRouterPlugin"> <description>主辅数据库路由插件</description> </bean> </list> </property> <property name="typeAliasesPackage" value="com.snailteam.crawler.model" /> <property name="transactionFactory"> <bean class="org.apache.ibatis.transaction.managed.ManagedTransactionFactory" /> </property> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="sqlSessionFactoryBeanName" value="crawlerSessionFactory" /> <property name="basePackage" value="com.snailteam.crawler.dao" /> <property name="markerInterface" value="com.snailteam.core.base.BaseDAO" /> </bean> <bean id="crawlerTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dynamicDataSource" /> </bean>
package org.springframework.jdbc.datasource; import java.util.Map; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; import org.springframework.jdbc.datasource.support.DynamicDataSourceHolder; /** * @author xiaofancn@gmail.com * @version 创建时间:2015-4-30 上午9:54:49 * 类说明 */ public class DynamicDataSource extends AbstractRoutingDataSource { @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public void setTargetDataSources(Map targetDataSources) { super.setTargetDataSources(targetDataSources); super.afterPropertiesSet(); } @Override protected Object determineCurrentLookupKey() { System.out.println(DynamicDataSourceHolder.getDataSourceName()); return DynamicDataSourceHolder.getDataSourceName(); } }
package org.springframework.jdbc.datasource.support; /** * @author xiaofancn@gmail.com * @version 创建时间:2015-4-30 上午9:56:09 类说明 */ public class DynamicDataSourceHolder { private static final ThreadLocal<String> holder = new ThreadLocal<String>(); public static void putDataSourceName(String name) { holder.set(name); } public static String getDataSourceName() { return holder.get(); } }
package com.snailteam.core.plugins; import java.lang.annotation.Annotation; import java.util.Date; import java.util.Map; import java.util.Properties; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.plugin.Intercepts; import org.apache.ibatis.plugin.Invocation; import org.apache.ibatis.plugin.Plugin; import org.apache.ibatis.plugin.Signature; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import org.apache.log4j.Logger; import org.springframework.jdbc.datasource.support.DynamicDataSourceHolder; import com.snailteam.core.annotation.Shard; import com.snailteam.core.utils.ReflectUtils; @Intercepts({ @Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class }), }) public class ShardDBRouterPlugin implements Interceptor { private static Logger logger = Logger.getLogger(ShardDBRouterPlugin.class); public Object intercept(Invocation invocation) throws Throwable { MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; invocation.getTarget(); // ReflectUtils.getFieldValue(statement, "delegate"); Object obj = invocation.getArgs()[1]; BoundSql boundSql = mappedStatement.getBoundSql(obj); if(boundSql.getParameterObject()!=null){ Object paramVal = obtainParam(boundSql.getParameterObject(), "side_id",mappedStatement.getConfiguration().isMapUnderscoreToCamelCase()); int sideID = Integer.valueOf(paramVal.toString()).intValue(); System.out.println((sideID%3)+""); DynamicDataSourceHolder.putDataSourceName((sideID%3)+""); } Object o = invocation.proceed(); return o; } public Object plugin(Object target) { return Plugin.wrap(target, this); } public void setProperties(Properties properties) { } private Object obtainParam(Object params, String column,boolean isCamelCase){ Object paramVal = null; if(params instanceof String || params instanceof Integer || params instanceof Byte || params instanceof Date){ paramVal = params; }else if(params instanceof Map){ paramVal = ((Map<String,Object>)params).get(camelCaseConvert(column)); }else{ boolean isShard = false; Annotation[] annotations = params.getClass().getDeclaredAnnotations(); if(annotations!=null && annotations.length >0){ for(Annotation annotation : annotations){ if(annotation instanceof Shard){ isShard = true; break; } } } if(isShard){ paramVal = ReflectUtils.getFieldValue(params, camelCaseConvert(column)); } } return paramVal; } public static String camelCaseConvert(String column){ logger.debug("===============列-属性映射处理======================"); String[] arr = column.split("_"); if(arr.length == 1){ return column; } else if(arr.length > 1) { StringBuilder sb = new StringBuilder(); for(String s:arr){ sb.append(s.substring(0,1).toUpperCase()).append(s.substring(1)); } String prop = sb.toString(); return prop.substring(0, 1).toLowerCase() + prop.substring(1); }else{ return null; } } }