您的位置:首页 > 编程语言 > Java开发

使用spring实现读写分离(mysql主从复制)四-优化改进切面实现,使用事务策略规则匹配

2017-12-15 09:53 896 查看
之前的实现我们是将通过方法名匹配,而不是使用事务策略中的定义,我们使用事务管理策略中的规则匹配,只需改动DataSourceAspect 切面类就可了

1.1. 改进后的配置

<!--
定义AOP切面处理器-->
<bean class="cn.itcast.usermanage.spring.DataSourceAspect" id="dataSourceAspect">
<!--
指定事务策略 -->
<property name="txAdvice" ref="txAdvice"/>
<!--
指定slave方法的前缀(非必须)-->
<property name="slaveMethodStart" value="query,find,get"/>
</bean>

1.2. 改进后的实现

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
 
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionAttribute;
import org.springframework.transaction.interceptor.TransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionInterceptor;
import org.springframework.util.PatternMatchUtils;
import org.springframework.util.ReflectionUtils;
 
/**
 *
定义数据源的AOP切面,该类控制了使用Master还是Slave。
 *

 *
如果事务管理中配置了事务策略,则采用配置的事务策略中的标记了ReadOnly的方法是用Slave,其它使用Master。
 *

 *
如果没有配置事务管理的策略,则采用方法名匹配的原则,以query、find、get开头方法用Slave,其它用Master。
 *

 *
@author zhijun
 *
 */
public class DataSourceAspect {
 
    private List<String>slaveMethodPattern =
new ArrayList<String>();
    
    private static final String[]defaultSlaveMethodStart =new String[]{"query",
"find",
"get" };
    
    private String[]slaveMethodStart;
 
    /**
     *
读取事务管理中的策略
     *

     *
@param txAdvice
     *
@throws Exception
     */
    @SuppressWarnings("unchecked")
    public void setTxAdvice(TransactionInterceptortxAdvice)
throws Exception {
        if (txAdvice ==null) {
            //没有配置事务管理策略
            return;
        }
        //从txAdvice获取到策略配置信息
        TransactionAttributeSource
transactionAttributeSource = txAdvice.getTransactionAttributeSource();
        if (!(transactionAttributeSource instanceof NameMatchTransactionAttributeSource))
{
            return;
        }
        //使用反射技术获取到NameMatchTransactionAttributeSource对象中的nameMap属性值
        NameMatchTransactionAttributeSourcematchTransactionAttributeSource = (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());
        }
    }
 
    /**
     *
在进入Service方法之前执行
     *

     *
@param point切面对象
     */
    public void before(JoinPointpoint) {
        //获取到当前执行的方法名
        String methodName =point.getSignature().getName();
 
        boolean isSlave =false;
 
        if (slaveMethodPattern.isEmpty()) {
            //当前Spring容器中没有配置事务策略,采用方法名匹配方式
            isSlave = isSlave(methodName);
        } else {
            //使用策略规则匹配
            for (String mappedName :slaveMethodPattern)
{
                if (isMatch(methodName,mappedName)) {
                    isSlave =true;
                    break;
                }
            }
        }
 
        if (isSlave) {
            //标记为读库
            DynamicDataSourceHolder.markSlave();
        } else {
            //标记为写库
            DynamicDataSourceHolder.markMaster();
        }
    }
 
    /**
     *
判断是否为读库
     *

     *
@param methodName
     *
@return
     */
    private Boolean isSlave(String methodName) {
        //方法名以query、find、get开头的方法名走从库
        return StringUtils.startsWithAny(methodName, getSlaveMethodStart());
    }
 
    /**
     *
通配符匹配
     *

     * Return if the given method name matches the mapped name.
     *
<p>
     * The default implementation checks for "xxx*", "*xxx"
and "*xxx*" matches, as well as direct
     * equality. Can be overridden in subclasses.
     *

     *
@param methodName the method name of the class
     *
@param mappedName the name in the descriptor
     *
@return if the names match
     *
@see org.springframework.util.PatternMatchUtils#simpleMatch(String,String)
     */
    protected boolean isMatch(String methodName,String mappedName)
{
        return PatternMatchUtils.simpleMatch(mappedName,methodName);
    }
 
    /**
     *
用户指定slave的方法名前缀
     *
@param slaveMethodStart
     */
    public void setSlaveMethodStart(String[]slaveMethodStart)
{
        this.slaveMethodStart =slaveMethodStart;
    }
 
    public String[] getSlaveMethodStart() {
        if(this.slaveMethodStart ==null){
            //没有指定,使用默认
            return defaultSlaveMethodStart;
        }
        return slaveMethodStart;
    }
    
}




上一篇   [b]使用spring实现读写分离(mysql主从复制)三:使用spring实现读写分离[/b]

下一篇  
 使用spring实现读写分离(mysql主从复制)五:一主多从的实现
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: