yinian 发表于 2017-12-13 08:38:34

使用Spring实现MySQL读写分离

/**  * 如果在spring配置了事务的策略,则标记了ReadOnly的方法用从库Slave, 其它使用主库Master。
  * 如果没有配置事务策略, 则采用方法名匹配, 以query、find、get开头的方法用Slave,其它用Master。
*/
  
public>  

  private List<String> slaveMethodPattern = new ArrayList<String>();//保存有readonly属性的带通配符方法名
  private static final String[] defaultSlaveMethodStartWith = new String[]{"query", "find", "get" };
  private String[] slaveMethodStartWith;//保存有slaveMethodStartWith属性的方法名头部
  //注入
  public void setTxAdvice(TransactionInterceptor txAdvice) throws Exception {
  if (txAdvice == null) {
  // 没有配置事务策略
  return;
  }
  //从txAdvice获取策略配置信息
  TransactionAttributeSource transactionAttributeSource = txAdvice.getTransactionAttributeSource();
  if (!(transactionAttributeSource instanceof NameMatchTransactionAttributeSource)) {
  return;
  }
  //使用反射技术获取到NameMatchTransactionAttributeSource对象中的nameMap属性值
  NameMatchTransactionAttributeSource matchTransactionAttributeSource = (NameMatchTransactionAttributeSource) transactionAttributeSource;
  Field nameMapField = ReflectionUtils.findField(NameMatchTransactionAttributeSource.class, "nameMap");
  nameMapField.setAccessible(true); //设置该字段可访问
  //获取nameMap的值
  Map<String, TransactionAttribute> map = (Map<String, TransactionAttribute>) nameMapField.get(matchTransactionAttributeSource);
  //遍历nameMap
  for (Map.Entry<String, TransactionAttribute> entry : map.entrySet()) {
  if (!entry.getValue().isReadOnly()) {   // 定义了ReadOnly的策略才加入到slaveMethodPattern
  continue;
  }
  slaveMethodPattern.add(entry.getKey());
  }
  }
  

  // 切面 before方法
  public void before(JoinPoint point) {
  // 获取到当前执行的方法名
  String methodName = point.getSignature().getName();
  

  boolean isSlave = false;
  

  if (slaveMethodPattern.isEmpty()) {
  // 没有配置read-only属性,采用方法名匹配方式
  isSlave = isSlaveByMethodName(methodName);
  } else {
  // 配置read-only属性, 采用通配符匹配
  for (String mappedName : slaveMethodPattern) {
  if (isSlaveByConfigWildcard(methodName, mappedName)) {
  isSlave = true;
  break;
  }
  }
  }
  if (isSlave) {
  // 标记为读库
  DynamicDataSource.markMaster(true);
  } else {
  // 标记为写库
  DynamicDataSource.markMaster(false);
  }
  }
  

  // 匹配以指定名称开头的方法名, 配置了slaveMethodStartWith属性, 或使用默认
  private Boolean isSlaveByMethodName(String methodName) {
  return StringUtils.startsWithAny(methodName, getSlaveMethodStartWith());
  }
  

  // 匹配带通配符"xxx*", "*xxx" 和 "*xxx*"的方法名, 源自配置了readonly属性的方法名
  protected boolean isSlaveByConfigWildcard(String methodName, String mappedName) {
  return PatternMatchUtils.simpleMatch(mappedName, methodName);
  }
  

  // 注入
  public void setSlaveMethodStartWith(String[] slaveMethodStartWith) {
  this.slaveMethodStartWith = slaveMethodStartWith;
  }
  

  public String[] getSlaveMethodStartWith() {
  if(this.slaveMethodStartWith == null){
  // 没有配置slaveMethodStartWith属性,使用默认
  return defaultSlaveMethodStartWith;
  }
  return slaveMethodStartWith;
  }
  
}
页: [1]
查看完整版本: 使用Spring实现MySQL读写分离