spring 多数据源动态切换

理解spring动态切换数据源,需要对spring具有一定的了解

工作中经常遇到读写分离,数据源切换的问题,那么以下是本作者实际工作中编写的代码  与大家分享一下!

  

1.定义注解 DataSource 

package com.gomecar.index.datasource;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 数据源切换注解
 * @author xiaotian
 *
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface DataSource {

    String value() default "read";

}

2. 定义切面DataSourceAspect

package com.gomecar.index.datasource;

import java.lang.reflect.Method;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;

/**
 * 用于数据库读写分离的切面
 * @author xiaotian
 *
 */
@Aspect
public class DataSourceAspect {

    //日志
    private Logger logger = Logger.getLogger(this.getClass());

    /**
     * 拦截目标方法,获取由@DataSource指定的数据源标识,设置到线程存储中以便切换数据源
     *
     * @param point
     * @throws Exception
     */
    public void intercept(JoinPoint point) throws Exception {
        Class<?> target = point.getTarget().getClass();
        MethodSignature signature = (MethodSignature) point.getSignature();
        for (Class<?> clazz : target.getInterfaces()) {
            resolveDataSource(clazz, signature.getMethod());
        }
        resolveDataSource(target, signature.getMethod());
    }

    /**
     * 提取目标对象方法注解和类型注解中的数据源标识
     *
     * @param clazz
     * @param method
     */
    private void resolveDataSource(Class<?> clazz, Method method) {
        try {
            Class<?>[] types = method.getParameterTypes();
            // 默认使用类型注解dataSourcePointcutdataSourcePointcut
            if (clazz.isAnnotationPresent(DataSource.class)) {
                DataSource source = clazz.getAnnotation(DataSource.class);
                DynamicDataSourceHolder.putDataSource(source.value());
            }
            // 方法注解可以覆盖类型注解
            Method m = clazz.getMethod(method.getName(), types);
            if (m != null && m.isAnnotationPresent(DataSource.class)) {
                DataSource source = m.getAnnotation(DataSource.class);
                DynamicDataSourceHolder.putDataSource(source.value());
            }
        } catch (Exception e) {
            logger.error("切换数据源error", e);
        }
    }



    //通知
    public void before(JoinPoint point)
    {
        Object target = point.getTarget();
        String method = point.getSignature().getName();
        //反射获取接口
        Class<?>[] classz = target.getClass().getInterfaces();
        //获取返回值类型 
        Class<?>[] parameterTypes = ((MethodSignature) point.getSignature())
                .getMethod().getParameterTypes();
        try {
            //获取方法
            Method m = classz[0].getMethod(method, parameterTypes);
            //根据方法上注解  获取只读数据库连接池 或者只写数据库连接池
            if (m != null && m.isAnnotationPresent(DataSource.class)) {
                //根据注解值获取数据库连接池
                DataSource data = m
                        .getAnnotation(DataSource.class);
                DynamicDataSourceHolder.putDataSource(data.value());
                System.out.println(data.value());
            }
            
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
}

 

3.获取动态数据源DynamicDataSource

package com.gomecar.index.datasource;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
 * 动态获取数据源
 * @author xiaotian
 *
 */
public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceHolder.getDataSouce();
    }

}

 

4.数据源持有者DynamicDataSourceHolder

package com.gomecar.index.datasource;
/**
 * 数据库连接池 持有者
 * 将数据库连接绑定到当前线程
 * @author xiaotian
 *
 */
public class DynamicDataSourceHolder {
    //绑定当前线程
    public static final ThreadLocal<String> holder = new ThreadLocal<String>();
    //设置数据源
    public static void putDataSource(String name) {
        holder.set(name);
    }
    //获取数据源
    public static String getDataSouce() {
        return holder.get();
    }
}

 

posted @ 2017-11-07 20:29  霄九天  阅读(578)  评论(0编辑  收藏  举报