`
dannyhz
  • 浏览: 394939 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

基于注解的Spring多数据源配置和使用

 
阅读更多
https://www.cnblogs.com/liujiduo/p/5004691.html

不仅讲了 多数据源 , 甚至讲了自定义注解,并在spring里用pointcut aop来拦截。

引用


可以看到AbstractRoutingDataSource获取数据源之前会先调用determineCurrentLookupKey方法查找当前的lookupKey,这个lookupKey就是数据源标识。
因此通过重写这个查找数据源标识的方法就可以让spring切换到指定的数据源了。
第一步:创建一个DynamicDataSource的类,继承AbstractRoutingDataSource并重写determineCurrentLookupKey方法,代码如下:

复制代码
1 public class DynamicDataSource extends AbstractRoutingDataSource {
2
3     @Override
4     protected Object determineCurrentLookupKey() {
5         // 从自定义的位置获取数据源标识
6         return DynamicDataSourceHolder.getDataSource();
7     }
8
9 }
复制代码
第二步:创建DynamicDataSourceHolder用于持有当前线程中使用的数据源标识,代码如下:

复制代码
1 public class DynamicDataSourceHolder {
2     /**
3      * 注意:数据源标识保存在线程变量中,避免多线程操作数据源时互相干扰
4      */
5     private static final ThreadLocal<String> THREAD_DATA_SOURCE = new ThreadLocal<String>();
6
7     public static String getDataSource() {
8         return THREAD_DATA_SOURCE.get();
9     }
10
11     public static void setDataSource(String dataSource) {
12         THREAD_DATA_SOURCE.set(dataSource);
13     }
14
15     public static void clearDataSource() {
16         THREAD_DATA_SOURCE.remove();
17     }
18
19 }
复制代码
第三步:配置多个数据源和第一步里创建的DynamicDataSource的bean,简化的配置如下:

复制代码
1 <!--创建数据源1,连接数据库db1 -->
2 <bean id="dataSource1" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
3     <property name="driverClassName" value="${db1.driver}" />
4     <property name="url" value="${db1.url}" />
5     <property name="username" value="${db1.username}" />
6     <property name="password" value="${db1.password}" />
7 </bean>
8 <!--创建数据源2,连接数据库db2 -->
9 <bean id="dataSource2" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
10     <property name="driverClassName" value="${db2.driver}" />
11     <property name="url" value="${db2.url}" />
12     <property name="username" value="${db2.username}" />
13     <property name="password" value="${db2.password}" />
14 </bean>
15 <!--创建数据源3,连接数据库db3 -->
16 <bean id="dataSource3" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
17     <property name="driverClassName" value="${db3.driver}" />
18     <property name="url" value="${db3.url}" />
19     <property name="username" value="${db3.username}" />
20     <property name="password" value="${db3.password}" />
21 </bean>
22
23 <bean id="dynamicDataSource" class="com.test.context.datasource.DynamicDataSource"> 
24     <property name="targetDataSources"> 
25         <map key-type="java.lang.String">
26             <!-- 指定lookupKey和与之对应的数据源 -->
27             <entry key="dataSource1" value-ref="dataSource1"></entry> 
28             <entry key="dataSource2" value-ref="dataSource2"></entry> 
29             <entry key="dataSource3 " value-ref="dataSource3"></entry> 
30         </map> 
31     </property> 
32     <!-- 这里可以指定默认的数据源 -->
33     <property name="defaultTargetDataSource" ref="dataSource1" /> 
34 </bean> 
复制代码
到这里已经可以使用多数据源了,在操作数据库之前只要DynamicDataSourceHolder.setDataSource("dataSource2")即可切换到数据源2并对数据库db2进行操作了。

示例代码如下:

复制代码
1 @Service
2 public class DataServiceImpl implements DataService {
3     @Autowired
4     private DataMapper dataMapper;
5
6     @Override
7     public List<Map<String, Object>> getList1() {
8         // 没有指定,则默认使用数据源1
9         return dataMapper.getList1();
10     }
11
12     @Override
13     public List<Map<String, Object>> getList2() {
14         // 指定切换到数据源2
15         DynamicDataSourceHolder.setDataSource("dataSource2");
16         return dataMapper.getList2();
17     }
18
19     @Override
20     public List<Map<String, Object>> getList3() {
21         // 指定切换到数据源3
22         DynamicDataSourceHolder.setDataSource("dataSource3");
23         return dataMapper.getList3();
24     }
25 }
复制代码
--------------------------------------------------------------------------------------华丽的分割线--------------------------------------------------------------------------------------------------

但是问题来了,如果每次切换数据源时都调用DynamicDataSourceHolder.setDataSource("xxx")就显得十分繁琐了,而且代码量大了很容易会遗漏,后期维护起来也比较麻烦。能不能直接通过注解的方式指定需要访问的数据源呢,比如在dao层使用@DataSource("xxx")就指定访问数据源xxx?当然可以!前提是,再加一点额外的配置^_^。
首先,我们得定义一个名为DataSource的注解,代码如下:

1 @Target({ TYPE, METHOD })
2 @Retention(RUNTIME)
3 public @interface DataSource {
4     String value();
5 }
然后,定义AOP切面以便拦截所有带有注解@DataSource的方法,取出注解的值作为数据源标识放到DynamicDataSourceHolder的线程变量中:

复制代码
1 public class DataSourceAspect {
2
3     /**
4      * 拦截目标方法,获取由@DataSource指定的数据源标识,设置到线程存储中以便切换数据源
5      *
6      * @param point
7      * @throws Exception
8      */
9     public void intercept(JoinPoint point) throws Exception {
10         Class<?> target = point.getTarget().getClass();
11         MethodSignature signature = (MethodSignature) point.getSignature();
12         // 默认使用目标类型的注解,如果没有则使用其实现接口的注解
13         for (Class<?> clazz : target.getInterfaces()) {
14             resolveDataSource(clazz, signature.getMethod());
15         }
16         resolveDataSource(target, signature.getMethod());
17     }
18
19     /**
20      * 提取目标对象方法注解和类型注解中的数据源标识
21      *
22      * @param clazz
23      * @param method
24      */
25     private void resolveDataSource(Class<?> clazz, Method method) {
26         try {
27             Class<?>[] types = method.getParameterTypes();
28             // 默认使用类型注解
29             if (clazz.isAnnotationPresent(DataSource.class)) {
30                 DataSource source = clazz.getAnnotation(DataSource.class);
31                 DynamicDataSourceHolder.setDataSource(source.value());
32             }
33             // 方法注解可以覆盖类型注解
34             Method m = clazz.getMethod(method.getName(), types);
35             if (m != null && m.isAnnotationPresent(DataSource.class)) {
36                 DataSource source = m.getAnnotation(DataSource.class);
37                 DynamicDataSourceHolder.setDataSource(source.value());
38             }
39         } catch (Exception e) {
40             System.out.println(clazz + ":" + e.getMessage());
41         }
42     }
43
44 }
复制代码
最后在spring配置文件中配置拦截规则就可以了,比如拦截service层或者dao层的所有方法:

复制代码
1 <bean id="dataSourceAspect" class="com.test.context.datasource.DataSourceAspect" />
2     <aop:config>
3         <aop:aspect ref="dataSourceAspect">
4             <!-- 拦截所有service方法 -->
5             <aop:pointcut id="dataSourcePointcut" expression="execution(* com.test.*.dao.*.*(..))"/>
6             <aop:before pointcut-ref="dataSourcePointcut" method="intercept" />
7         </aop:aspect>
8     </aop:config>
9 </bean>
复制代码
OK,这样就可以直接在类或者方法上使用注解@DataSource来指定数据源,不需要每次都手动设置了。

示例代码如下:

复制代码
1 @Service
2 // 默认DataServiceImpl下的所有方法均访问数据源1
3 @DataSource("dataSource1")
4 public class DataServiceImpl implements DataService {
5     @Autowired
6     private DataMapper dataMapper;
7
8     @Override
9     public List<Map<String, Object>> getList1() {
10         // 不指定,则默认使用数据源1
11         return dataMapper.getList1();
12     }
13
14     @Override
15     // 覆盖类上指定的,使用数据源2
16     @DataSource("dataSource2")
17     public List<Map<String, Object>> getList2() {
18         return dataMapper.getList2();
19     }
20
21     @Override
22     // 覆盖类上指定的,使用数据源3
23     @DataSource("dataSource3")
24     public List<Map<String, Object>> getList3() {
25         return dataMapper.getList3();
26     }
27 }
复制代码
提示:注解@DataSource既可以加在方法上,也可以加在接口或者接口的实现类上,优先级别:方法>实现类>接口。也就是说如果接口、接口实现类以及方法上分别加了@DataSource注解来指定数据源,则优先以方法上指定的为准。


分享到:
评论

相关推荐

    基于注解和Spring的多数据源配置和使用

    本篇文章将深入探讨如何基于注解和Spring实现多数据源配置和使用。 首先,我们需要理解"注解"在Java中的作用。注解是一种元数据,它提供了一种安全的方法来关联信息和代码(类、方法、变量等)。Spring框架广泛使用...

    spring数据源配置

    Spring框架支持多种数据源的配置方式,包括但不限于基于XML的配置、基于注解的配置以及基于Java配置的方式。本文主要关注基于XML的配置方法。 #### 三、XML配置详解 ##### 1. 数据源配置 数据源的配置通常涉及到...

    spring boot多数据源配置

    在Spring Boot应用中,多数据源配置是一项关键的技术,它允许我们同时管理多个数据库,比如主库和从库,或者不同类型的数据库。本教程将详细阐述如何在Spring Boot项目中实现这一功能,从数据源配置、实体管理到...

    SSM(Spring+SpringMVC+MyBatis)多数据源配置框架

    在多数据源配置中,Spring能够帮助管理不同的数据源,通过配置bean来切换和控制数据源的使用。 **SpringMVC** 是Spring框架的一部分,专为Web开发设计。它简化了模型-视图-控制器(Model-View-Controller,MVC)的...

    SpringBoot配置多数据源实现动态切换数据源

    SpringBoot实现多数据源主要依靠Spring的`@Configuration`和`@DataSourceConfiguration`注解,以及Spring JDBC的`DataSource`接口。下面是一个基本的配置示例: ```java @Configuration public class ...

    使用注解配置Spring多数据源

    本教程将详细介绍如何使用注解来配置Spring的多数据源,结合spring、restlet和mysql环境进行实战演示。在开始之前,请确保已经执行了提供的`mysql_dml.sql`文件,以初始化必要的测试数据。 首先,我们需要理解...

    springboot多数据源配置

    在Spring Boot应用中,多数据源配置是一项重要的技术实践,特别是在大型系统中,可能需要连接到多个数据库以实现数据隔离、读写分离或是分布式事务管理。Spring Boot以其强大的自动化配置能力,使得设置多数据源变得...

    Spring Boot+Jpa多数据源配置Demo(支持不同数据库)

    Spring Boot结合JPA(Java Persistence API)和JdbcTemplate,为开发者提供了灵活且强大的多数据源配置能力。本示例将详细介绍如何在Spring Boot项目中实现这样的配置,以支持不同类型的数据库。 首先,我们要理解...

    基于Spring多数据源实例

    5. **编程或声明式数据源切换**:在业务代码中,可以使用Spring的`@Resource`注解注入DataSource,然后根据需求手动切换,或者通过AOP和Spring的代理机制自动处理数据源的切换。 6. **测试与优化**:最后,对整个...

    Spring多数据源配置

    通过上述步骤,我们可以实现在Spring环境中配置多个数据源、SessionFactory和TransactionManager的目标。这对于构建复杂的企业级应用、优化数据库性能以及提高系统的可伸缩性具有重要意义。然而,需要注意的是,多...

    Spring 数据源不同配置

    如果使用Spring Data JPA或Hibernate,数据源配置更为简单,因为它们会自动创建并管理数据源。Spring Data JPA通过`spring-boot-starter-data-jpa`依赖自动配置了JPA和HikariCP数据源。 总的来说,Spring提供了...

    spring boot多数据源(AOP注解动态切换)

    通过以上步骤,我们成功地在Spring Boot中实现了基于AOP注解的多数据源动态切换。这使得在运行时可以根据业务需求选择合适的数据源,提高了代码的灵活性和可维护性。在实际项目中,你可能还需要考虑事务管理、数据源...

    Spring Boot使用spring-data-jpa配置Mysql多数据源

    在Spring Boot应用中,使用`spring-data-jpa`来配置MySQL多数据源是一项常见的需求,尤其是在构建大型分布式系统时,为了实现数据隔离、负载均衡或读写分离等目的。本教程将详细介绍如何在Spring Boot项目中配置多个...

    Spring+SpringMvc+MybatisPlus+Aop(自定义注解)动态切换数据源

    - 数据源相关的Java配置类,用于配置Spring的DataSource和MybatisPlus。 - Mapper接口和对应的XML文件,定义数据库操作。 - 业务逻辑层的Java类,其中的方法使用了自定义注解来切换数据源。 通过这样的设计,项目...

    Spring Boot多数据源(JdbcTemplate)配置与使用

    在本教程中,我们将深入探讨如何在Spring Boot项目中配置和使用多数据源以及JdbcTemplate。 首先,让我们了解什么是`JdbcTemplate`。它是Spring提供的一种模板类,用于执行SQL语句,通过回调机制将结果转换为Java...

    java spring 多数据源

    本教程将深入探讨如何在Spring中配置和管理多个数据源,并以MySQL为例进行实战演示。 首先,我们需要理解Spring Boot对数据源的默认支持。Spring Boot通过`spring.datasource.*`的配置属性简化了数据库连接的设置,...

    Spring配置多个数据源

    通过以上步骤,你可以在Spring应用中成功配置和使用多个数据源。这使得你的系统更具扩展性和灵活性,能够适应复杂的企业级需求。记住,正确管理和配置数据源对于系统的稳定性和性能至关重要,因此在实际操作时一定要...

    使用注解配置实现Spring动态数据源切换

    使用注解配置实现Spring动态数据源切换,实现原理 1、自定义动态数据源类DynamicDataSource: 实现spring类AbstractRoutingDataSource的方法determineCurrentLookupKey 2、自定义Spring AOP类DataSourceAspect 3、...

    spring boot 2多数据源,里面有hibernate和mybatis的多数据源代码

    这些代码可以直接集成到你的项目中,只需要调整为匹配你的数据库配置,就可以实现Spring Boot 2下的多数据源支持,同时利用Hibernate和MyBatis的优势。 总之,多数据源的实现是Spring Boot 2应用中的高级特性,它...

Global site tag (gtag.js) - Google Analytics