数据库读写分离(aop方式完整实现)

最近项目要支持读写分离, 网上找了很多,但都是不太完整,我自己整理了下供大家参考。
我的项目使用的框架: springMvc+spring+hibernate+springJPA+maven, 数据库连接池用阿里的druid。


1. 新建一个DynamicDataSource类, 继承springAbstractRoutingDataSource 类,

并重写determineCurrentLookupKey()方法,如下: 

package com.dataSource;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**
 * 数据源动态切换类
 * 

* Copyright: Copyright (c) 2015-3-9 下午3:15:19 *

* Company: *

* * @author [email protected] * @version 1.0.0 */ public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DataSourceSwitcher.getDataSource(); } }


2. 新建DataSourceSwitcher类, 实现数据源选择:

package com.dataSource;

import org.springframework.util.Assert;

/**
 * 数据源选择类
 * 

* Copyright: Copyright (c) 2015-3-9 下午3:14:55 *

* Company: *

* * @author [email protected] * @version 1.0.0 */ public class DataSourceSwitcher { private static final ThreadLocal contextHolder = new ThreadLocal(); /** 主库(写库) **/ public static final String MASTER_DATA_SOURCE = "master"; /** 从库(读库) **/ public static final String SLAVE_DATA_SOURCE = "slave"; public static void setDataSource(String dataSource) { Assert.notNull(dataSource, "dataSource cannot be null"); contextHolder.set(dataSource); } public static void setMaster() { clearDataSource(); } public static void setSlave() { setDataSource(SLAVE_DATA_SOURCE); } public static String getDataSource() { return (String) contextHolder.get(); } public static void clearDataSource() { contextHolder.remove(); } }


 

3. 新建切面类, 判断如果调用方法以query,list,get方法开头的, 切换为查询库: 

package com.dataSource;

import java.lang.reflect.Method;
import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.ThrowsAdvice;

/**
 * 配置AOP切面类,动态切换读/写数据库。
 * 

* Copyright: Copyright (c) 2015-3-9 下午3:16:51 *

* Company: *

* * @author [email protected] * @version 1.0.0 */ public class DataSourceAdvice implements MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice { private static final Logger log = Logger.getLogger(DataSourceAdvice.class); private String logInfo; // 需要切换到从库(读库)的方法名前缀 private List slaveMethods; /** * service方法执行之前被调用. */ @Override public void before(Method method, Object[] args, Object target) throws Throwable { logInfo = String.format("before切入点:%s-->%s(),切换到:", target.getClass().getName(), method.getName()); String methodName = method.getName(); boolean hasSwitchedSlave = false; for (String slaveMethod : slaveMethods) { if (methodName.startsWith(slaveMethod)) { if (log.isDebugEnabled()) { log.debug(logInfo + DataSourceSwitcher.SLAVE_DATA_SOURCE); } hasSwitchedSlave = true; DataSourceSwitcher.setSlave(); break; } } if (!hasSwitchedSlave) { if (log.isDebugEnabled()) { log.debug(logInfo + "切换到:" + DataSourceSwitcher.MASTER_DATA_SOURCE); } DataSourceSwitcher.setMaster(); } } /** * service方法执行完之后被调用. */ @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { } /** * 抛出Exception之后被调用。 * * @param method * @param args * @param target * @param ex * @throws Throwable */ public void afterThrowing(Method method, Object[] args, Object target, Exception ex) throws Throwable { logInfo = String.format("after throwing:%s类中%s方法,", target.getClass().getName(), method.getName()); log.error(logInfo + "发生异常:" + ex.getMessage() + ",切换到:" + DataSourceSwitcher.SLAVE_DATA_SOURCE); DataSourceSwitcher.setSlave(); } public List getSlaveMethods() { return slaveMethods; } public void setSlaveMethods(List slaveMethods) { this.slaveMethods = slaveMethods; } }




4.  spring配置文件中, 配置数据源:

 数据库读写分离(aop方式完整实现)_第1张图片

 

 

5. AOP配置(注意, 可以在service层切换(推荐), 也可以在控制器层切换):

截图为在控制层切换配置, 附件中的context.xml中给的是在service/dao层切换的配置方式。

数据库读写分离(aop方式完整实现)_第2张图片

6.  mvc层支持aop(如果aop切换配置在控制层, 则需要配置这步):

数据库读写分离(aop方式完整实现)_第3张图片

7. 特殊类可以硬编码:

      切换到主库 : DataSourceSwitcher.setMaster();

      比如 , 登录拦截器RoleGenInterceptor.java --> genLocalSession()

数据库读写分离(aop方式完整实现)_第4张图片



 附件下载地址

你可能感兴趣的:(java)