druid多数据源配置+Datasurce动态切换

博客引用处(以下内容在原有博客基础上进行补充或更改,谢谢这些大牛的博客指导):
Datasource动态切换

AbstractRoutingDataSource 数据源动态切换

spring 使用AbstractRoutingDataSource自定义动态数据源时的事务处理, 需要继承spring的AbstractRoutingDataSource定义自己的动态数据源,可以根据需要动态的切换不同数据库的数据源,使用起来非常方便。

public class ChooseDataSource extends AbstractRoutingDataSource {

	/**
	 * 获取与数据源相关的key
	 * 此key是Map resolvedDataSources 中与数据源绑定的key值
	 * 在通过determineTargetDataSource获取目标数据源时使用
	 */
	@Override
	protected Object determineCurrentLookupKey() {
		return RouteHolder.getRouteKey();
	}

}

通过容器RouteHolder存储当前线程使用的数据源的key

/**
 * 保存当前线程数据源的key
 */
public class RouteHolder {
	private static ThreadLocal routeKey = new ThreadLocal();
	
	/**
	 * 获取当前线程的数据源路由的key
	 * @return
	 */
	public static String getRouteKey()
	{
		String key = routeKey.get();
		return key;
	}
	/**
	 * 绑定当前线程数据源路由的key
	 * 在使用完成之后,必须调用removeRouteKey()方法删除
	 * @param key
	 */
	public static void  setRouteKey(String key)
	{
		routeKey.set(key);
	}
	
	/**
	 * 删除与当前线程绑定的数据源路由的key
	 */
	public static void removeRouteKey()
	{
		routeKey.remove();
	}
}

使用spring 的aop编程在业务逻辑方法运行前将当前方法使用数据源的key从业务逻辑方法上自定义注解@DataSource中解析数据源key并添加到RouteHolder中

/**
 * 执行dao方法之前的切面
 * 获取datasource对象之前往RouteHolder中指定当前线程数据源路由的key
 *
 */
public class DataSourceAspect {


    /**
     * 在dao层方法之前获取datasource对象之前在切面中指定当前线程数据源路由的key
     */
    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 {
            if(classz != null && classz.length > 0) {
            Method m = classz[0].getMethod(method, parameterTypes);
            if (m != null && m.isAnnotationPresent(DataSource.class)) {
                DataSource data = m.getAnnotation(DataSource.class);
                RouteHolder.setRouteKey(data.value());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

解释:
DataSourceAspect 这个切面类,应该针对的被代理类应该是service的实现类(serviceImpl),因为dao层用的mybatis只有一个dao层的接口,所以放在service上做处理比较好。
druid多数据源配置+Datasurce动态切换_第1张图片
业务逻辑方法

@Named("userService")
public class UserService 
{
	@Inject
	private UserDao userDao;
	
	@DataSource("master")
	@Transactional(propagation=Propagation.REQUIRED)
	public void updatePasswd(int userid,String passwd)
	{
		User user = new User();
		user.setUserid(userid);
		user.setPassword(passwd);
		userDao.updatePassword(user);
	}
	@DataSource("slave")
	@Transactional(propagation=Propagation.REQUIRED)
	public User getUser(int userid)
	{
		User user = userDao.getUserById(userid);
		System.out.println("username------:"+user.getUsername());
		return user;
	}
}

注解类

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
 * RUNTIME
 * 编译器将把注释记录在类文件中,在运行时 VM 将保留注释,因此可以反射性地读取。
 * @author jiangxm
 *
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DataSource {
    String value();
}

spring的配置文件


		
				
				   
				   
				   
				   
				
			
	
	
	
	  
          
          
          
          
          
          
          
      
    
      
          
          
          
          
          
          
          
    
      
      
      
      
        
    
      
          
          
     
    
    
    
      
    
   
   
   
   	
    
    
    	
    	   	
    	   	
    	
    
   
   
    
      
          
     
	  
    

事务管理配置一定要配置在往RouteHolder中注入数据源key之前 否则会报 Could not open JDBC Connection for transaction; nested exception is java.lang.IllegalStateException: Cannot determine target DataSource for lookup key [null] 找不到数据源错误。

由此就可以根据方法上的@DataSource(“master”) 注解配置不同的数据源key 使用动态数据源。

解释:

  • java.lang.reflect.Method.getAnnotation(Class annotationClass)
    参数
    annotationClass - Class对象对相应的注解类型,比如Datasource.class 。
    返回值
    如果存在于此元素,则返回该元素注解指定的注解对象,否则返回为null
    引用
    https://www.yiibai.com/javareflect/javareflect_method_getannotation.html

例子:

import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;

public class MethodDemo {
   public static void main(String[] args) {
      Method[] methods = SampleClass.class.getMethods();

      Annotation annotation = methods[0].getAnnotation(CustomAnnotation.class);
      if(annotation instanceof CustomAnnotation){
         CustomAnnotation customAnnotation = (CustomAnnotation) annotation;
         System.out.println("name: " + customAnnotation.name());
         System.out.println("value: " + customAnnotation.value());
      }
   }
}

@CustomAnnotation(name="SampleClass",  value = "Sample Class Annotation")
class SampleClass {
   private String sampleField;

   @CustomAnnotation(name="getSampleMethod",  value = "Sample Method Annotation")
   public String getSampleField() {
      return sampleField;
   }

   public void setSampleField(String sampleField) {
      this.sampleField = sampleField;
   } 
}

@Retention(RetentionPolicy.RUNTIME)
@interface CustomAnnotation {
   public String name();
   public String value();
}

编译并运行上面的程序,这将产生以下结果

 -name: getSampleMethod
  value: Sample Method Annotation
  • getInterfaces()
    能够获得这个对象所实现的接口

你可能感兴趣的:(java相关)