SpringAOP实现mysql读写分离

1、工作原理
在调用serivce服务之前通过AOP判断,方法是读库操作还是写库操作。根据判断方法名,调用不同的数据库。例如使用query、find、get等开头的方法就访问读库,其他的访问写库。
2、配置文件配置多数据源

<bean id="dataSource" class="xyz.chanjkf.aop.DynamicDataSource">
    <property name="targetDataSources">
    <!-- 设置多个数据源 -->
        <map key-type="java.lang.String">
            <!-- 这个key需要和程序中的key一致 -->
            <entry key="master" value-ref="masterDataSource"/>
            <entry key="slave" value-ref="slave01DataSource" />
        </map>
    </property>
    <!-- 设置默认的数据源,这里默认走写库 -->
    <property name="defaultTargetDataSource" ref="masterDataSource"/>
</bean>

<bean id="slave01DataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
    <constructor-arg>
        <bean class="com.zaxxer.hikari.HikariConfig">
            <property name="driverClassName" value="${hibernate.master.connection.driverClass}"/>
            <property name="jdbcUrl" value="${hibernate.master.connection.url}"/>
            <property name="username" value="${hibernate.master.connection.username}"/>
            <property name="password" value="${hibernate.master.connection.password}"/>
            <property name="readOnly" value="false" />
            <property name="connectionTimeout" value="${jdbc.connectionTimeout}"/>
            <property name="idleTimeout" value="${jdbc.idleTimeout}"/>
            <property name="maxLifetime" value="${jdbc.maxLifetime}"/>
            <property name="maximumPoolSize" value="${jdbc.maximumPoolSize}"/>
        </bean>
    </constructor-arg>
</bean>
<bean id="masterDataSource"
      class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
    <constructor-arg>
        <bean class="com.zaxxer.hikari.HikariConfig">
            <property name="driverClassName" value="${hibernate.slave.connection.driverClass}"/>
            <property name="jdbcUrl" value="${hibernate.slave.connection.url}"/>
            <property name="username" value="${hibernate.slave.connection.username}"/>
            <property name="password" value="${hibernate.slave.connection.password}"/>
            <property name="readOnly" value="false" />
            <property name="connectionTimeout" value="${jdbc.connectionTimeout}"/>
            <property name="idleTimeout" value="${jdbc.idleTimeout}"/>
            <property name="maxLifetime" value="${jdbc.maxLifetime}"/>
            <property name="maximumPoolSize" value="${jdbc.maximumPoolSize}"/>
        </bean>
    </constructor-arg>
</bean>

在配置文件dataSource中指定使用自己实现的数据源DynamicDataSource
3、配置aop切面

<bean class="xyz.chanjkf.aop.dataSourceAspect" id="dataSourceAspect">
    <aop:aspectj-autoproxy proxy-target-class="true" />
    <aop:config expose-proxy="true">
        <!--<aop:pointcut id="allManagerMethod" expression="execution(* xyz.chanjkf.service..*.*(..))" />-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="allManagerMethod"/>
        <aop:aspect ref="dataSourceAspect" order="1">
            <aop:pointcut id="allManagerMethod" expression="execution(* xyz.chanjkf.service..*.*(..))" />
            <aop:before method="before" pointcut-ref="allManagerMethod"/>
        </aop:aspect>
    </aop:config>

4、aop切面

public class dataSourceAspect {
    public void before(JoinPoint point){
        String methodName = point.getSignature().getName();
        if (isSalve(methodName)){
            DynamicDataSourceHolder.setSlave();
        } else {
            DynamicDataSourceHolder.setMaster();
        }
    }
    private boolean isSalve(String methodName) {
        String[] salveMethod = new String[]{"find","get","query"};
        return StringUtils.startsWithAny(methodName,salveMethod);
    }
}

5、配置数据源工具类

public class DynamicDataSourceHolder {
/**
 * 使用ThreadLocal技术来记录当前线程中的数据源的key,保证线程安全
 */
    //写库对应的数据源key
    private static final String MASTER = "master";
    //读库对应的数据源key
    private static final String SLAVE = "slave";
    private static final ThreadLocal<String>local = new ThreadLocal<String>();
    private static void saveDataBaseKey(String key) {
        local.set(key);
    }
    public static void setSlave(){
        saveDataBaseKey(SLAVE);
    }
    public static void setMaster() {
        saveDataBaseKey(MASTER);
    }
    public static String getKey() {
        return local.get();
    }
}

6、自定义数据源

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceHolder.getKey();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值