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">
            
            <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: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 ThreadLocallocal = new ThreadLocal();
    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();
    }
}

你可能感兴趣的:(java)