您的位置:首页 > 数据库

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

2015-06-12 15:14 501 查看
最近项目要支持读写分离, 网上找了很多,但都是不太完整,我自己整理了下供大家参考。

我的项目使用的框架: springMvc+spring+hibernate+springJPA+maven, 数据库连接池用阿里的druid。

1. 新建一个DynamicDataSource类, 继承spring的AbstractRoutingDataSource 类,

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

package com.dataSource;

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

/**
* 数据源动态切换类
* <p>
* Copyright: Copyright (c) 2015-3-9 下午3:15:19
* <p>
* Company:
* <p>
*
* @author macl@c-platform.com
* @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;

/**
* 数据源选择类
* <p>
* Copyright: Copyright (c) 2015-3-9 下午3:14:55
* <p>
* Company:
* <p>
*
* @author macl@c-platform.com
* @version 1.0.0
*/
public class DataSourceSwitcher {

private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();

/** 主库(写库) **/
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切面类,动态切换读/写数据库。
* <p>
* Copyright: Copyright (c) 2015-3-9 下午3:16:51
* <p>
* Company:
* <p>
*
* @author macl@c-platform.com
* @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<String> 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<String> getSlaveMethods() {
return slaveMethods;
}

public void setSlaveMethods(List<String> slaveMethods) {
this.slaveMethods = slaveMethods;
}
}


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



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

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



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



7. 特殊类可以硬编码:

切换到主库 : DataSourceSwitcher.setMaster();
比如 , 登录拦截器RoleGenInterceptor.java --> genLocalSession()



附件下载地址
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: