spring 配置多数据源(mysql读写分离)

内容预览:
  •   注:注意上面的通过反射获取业务方法的代码, 开始的时候用   Met...~
  • 后来在网上搜了下,大概说是这种方法获取的是代理方法,不是目标方法~
  •     5、下面看下 DataSourceContext 类,作用自然就是设置...~

 

  前段时间刚换了家新公司,然后看项目代码里用了数据库读写分离的架构,然后好奇扒了代码简单看了下,总体来说就是运用spring aop切面方式来实现的。看明白后就在自己的个人小项目里运用了下,测试OK,所以下面总结下流程:

  1、首先定义一个数据源注解,它有两个值,一个对应写库(主库),一个对应读库(从库)

package com.jdd.ds;


import java.lang.annotation.*;

@Target()
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {

String DATA_SOURCE_READ
= "dataSourceRead";
String DATA_SOURCE_WRITE
= "dataSourceWrite";

String name()
default "dataSourceWrite";
}

 

  2、在需要拦截的方法上加上该注解

package com.jdd.service.impl;

import com.jdd.dao.UserDao;
import com.jdd.ds.DataSource;
import com.jdd.pojo.User;
import com.jdd.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service(
"userService")
public class UserServiceImpl implements UserService{

@Autowired
private UserDao userDao;

@DataSource(name
=DataSource.DATA_SOURCE_READ)
@Override
public User getUserByNameAndPassword(String name, String password) {
return userDao.getUserByNameAndPassword(name, password);
}

@DataSource(name
=DataSource.DATA_SOURCE_WRITE)
@Override
public int insertUser(User user) {
return userDao.insertUser(user);
}
}

 

  3、然后在配置文件里加上aop切面配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context
="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop
="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation
="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">

<!-- 扫描包加载Service实现类 -->
<context:component-scan base-package="com.jdd.service"></context:component-scan>

<bean id="dataSourceExchange" class="com.jdd.ds.DataSourceExchange"></bean>
<aop:config>
<aop:aspect ref="dataSourceExchange">
<aop:around method="execute" pointcut="within(com.jdd.service.impl.*)"></aop:around>
</aop:aspect>
</aop:config>

</beans>

 

  4、然后我们要在切面类里,获取到方法上的dataSource注解里设置的值,从而决定使用哪个数据源

package com.jdd.ds;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;

public class DataSourceExchange {

private static Logger logger = LoggerFactory.getLogger(DataSourceExchange.class);

public Object execute(ProceedingJoinPoint pjp){

logger.info(
"DataSourceExchange==>");
Object obj
= null;

Signature signature
= pjp.getSignature();
MethodSignature methodSignature
= (MethodSignature)signature;
Method targetMethod
= methodSignature.getMethod();
Method realMethod
= null;
try {
realMethod
= pjp.getTarget().getClass().getDeclaredMethod(signature.getName(), targetMethod.getParameterTypes());
if(realMethod.isAnnotationPresent(DataSource.class)){
DataSource datasource
= (DataSource) realMethod.getAnnotation(DataSource.class);
DataSourceContext.setDbType(datasource.name());
logger.info(realMethod.getName()
+" set dbtype==>"+datasource.name());
}
else{
DataSourceContext.setDbType(
"dataSourceWrite");
}
obj
= pjp.proceed();
}
catch (Throwable t) {
t.printStackTrace();
}
logger.info(realMethod.getName()
+" clear datatype==>");
DataSourceContext.clearDbType();
return obj;

}

}

  在方法执行前,设置具体数据源,然后方法执行完后,再清除掉该值。

  注:注意上面的通过反射获取业务方法的代码, 开始的时候用

  MethodSignature signature = (MethodSignature)pjp.getSignature();

  Method method = signature.getMethod();

  发现通过这种方法获取的method,它是没有注解信息的。后来在网上搜了下,大概说是这种方法获取的是代理方法,不是目标方法。代理方法是不带注解信息的,所以这块注意下。

 

  5、下面看下 DataSourceContext 类,作用自然就是设置数据源上下文。

package com.jdd.ds;

public class DataSourceContext {

public static final String DATA_SOURCE_READ = "dataSourceRead";
public static final String DATA_SOURCE_WRITE = "dataSourceWrite";
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();

public DataSourceContext(){
}

public static void setDbType(String dbType){
contextHolder.set(dbType);
}

public static String getDbType(){
return (String)contextHolder.get();
}

public static void clearDbType(){
contextHolder.remove();
}

}

 

  6、下面定义 MultipleDataSource类, 继承与spring的 AbstractRoutingDataSource类, 并重写它的 determineCurrentLookupKey 方法, 作用就是从上下文获取当前线程使用的数据源标识:

package com.jdd.ds;

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

public class MultipleDataSource extends AbstractRoutingDataSource{

@Override
protected Object determineCurrentLookupKey() {

Object key
= DataSourceContext.getDbType();
if(key != null){
this.logger.info("当前线程使用的数据源标识为 [ " + key.toString() + " ].");
}
return key;
}
}

 

  7、最后在 配置文件 applicationContext-mysql.xml 里 配上数据源

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context
="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop
="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation
="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">

<!-- 加载配置文件 -->
<context:property-placeholder location="classpath:resource/*.properties" />

<!-- 数据库连接池 -->
<bean id="dataSourceWrite" class="com.alibaba.druid.pool.DruidDataSource"
destroy
-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="$" />
<property name="username" value="$" />
<property name="password" value="$" />
<property name="maxActive" value="10" />
<property name="minIdle" value="5" />
</bean>

<bean id="dataSourceRead" class="com.alibaba.druid.pool.DruidDataSource"
destroy
-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="$" />
<property name="username" value="$" />
<property name="password" value="$" />
<property name="maxActive" value="10" />
<property name="minIdle" value="5" />
</bean>
<bean id="multipleDataSource" class="com.jdd.ds.MultipleDataSource">
<property name="defaultTargetDataSource" ref="dataSourceWrite" />
<property name="targetDataSources">
<map>
<entry value-ref="dataSourceWrite" key="dataSourceWrite"></entry>
<entry value-ref="dataSourceRead" key="dataSourceRead"></entry>
</map>
</property>
</bean>
<!-- sqlsessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml"></property>
<property name="dataSource" ref="multipleDataSource"></property>
<property name="mapperLocations" value="classpath:com/jdd/mapper/*.xml"></property>
</bean>

</beans>

 

  8、到这里和spring相关的配置基本就配完了, 其实后面还要再配置一下 mysql的主从复制,就是对写库的操作都同步到从库,这样写库从库的数据才一致。具体配置操作我就不写了,可以自行到网上搜索。

 

以上就是:spring 配置多数据源(mysql读写分离) 的全部内容。

本站部分内容来源于互联网和用户投稿,如有侵权请联系我们删除,谢谢。
Email:[email protected]


0 条回复 A 作者 M 管理员
    所有的伟大,都源于一个勇敢的开始!
欢迎您,新朋友,感谢参与互动!欢迎您 {{author}},您在本站有{{commentsCount}}条评论