GHGL项目总结-spring+mybatis多数据库源
来源:互联网 发布:幽浮2知乎 编辑:程序博客网 时间:2024/06/07 14:58
项目需求所在,项目需要去另一个数据库中读写数据。解决方案很简单,动态配置数据源
spring框架中有这样的接口来切换数据源,创建一个DynamicDataSource的类,继承AbstractRoutingDataSource并重写determineCurrentLookupKey方法,代码:
public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DynamicDataSourceHolder.getDataSouce(); } }
然后,创建DynamicDataSourceHolder用于持有当前线程中使用的数据源标识
/** * 为数据源分配线程 * @author xw * */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(); } }
spring-jdbc.xml配置文件中
<bean name="masterdataSource" class="org.apache.commons.dbcp.BasicDataSource"> <!-- 数据库驱动类名。 --> <property name="driverClassName" value="${jdbc1.driverClass}" /> <!-- 连接数据库时使用的URL。 --> <property name="url" value="${jdbc1.jdbcUrl}" /> <!-- 连接数据库时使用的用户名。 --> <property name="username" value="${jdbc1.user}" /> <!-- 连接数据库时使用的用户密码。 --> <property name="password" value="${jdbc1.password}" /> </bean> <bean name="slavedataSource" class="org.apache.commons.dbcp.BasicDataSource"> <!-- 数据库驱动类名。 --> <property name="driverClassName" value="${jdbc2.driverClass}" /> <!-- 连接数据库时使用的URL。 --> <property name="url" value="${jdbc2.jdbcUrl}" /> <!-- 连接数据库时使用的用户名。 --> <property name="username" value="${jdbc2.user}" /> <!-- 连接数据库时使用的用户密码。 --> <property name="password" value="${jdbc2.password}" /> </bean> <bean id="dataSource" class="com.djzh.core.dataSource.DynamicDataSource"> <property name="targetDataSources"> <map key-type="java.lang.String"> <entry key="master" value-ref="masterdataSource" /> <entry key="slave" value-ref="slavedataSource" /> </map> </property> </bean>
在jdbc.properties文件中配置数据库
jdbc1.driverClass=com.mysql.jdbc.Driverjdbc1.jdbcUrl=jdbc:mysql://192.168.26.1:3306/test1?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNulljdbc1.user=1jdbc1.password=1jdbc2.driverClass=com.mysql.jdbc.Driverjdbc2.jdbcUrl=jdbc:mysql://192.168.26.1/test2?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNulljdbc2.user=1jdbc2.password=1
在代码逻辑层中写
DynamicDataSourceHolder.putDataSource("master");
基本就可以动态切换数据库。
每次写逻辑时都要写这句话,所以用更方便的方式来优化一下,那就是注解
用aop拦截方法然后设置数据库源,在到层设置更加灵活,
aop拦截方法类:
/** * Aop实现动态对数据源的参数赋值以获取不同数据源 * @author xw * */public class DataSourceAspect { public void before(JoinPoint point) { Object target = point.getTarget(); String method = point.getSignature().getName(); Class<?>[] classz = target.getClass().getInterfaces(); //Class<?> classz = target.getClass(); 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()); } } catch (Exception e) { e.printStackTrace(); } } }
spring-aop.xml配置文件:
<!-- 配置数据库注解aop --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> <bean id="manyDataSourceAspect" class="com.djzh.core.dataSource.DataSourceAspect" /> <aop:config> <aop:aspect id="c" ref="manyDataSourceAspect"> <aop:pointcut id="tx" expression="execution(* com.djzh.core.dao.*.*(..))"/> <aop:before pointcut-ref="tx" method="before"/> </aop:aspect> </aop:config>
这样在dao接口方法上写上如下注解
@DataSource("master")
就可以了。
其中遇到的问题:
测试的时候遇到这样
刚开始的时候aop拦截的是service层方法,然后进行以下的测试:
public static void main(String args[]){
@SuppressWarnings("resource")
AbstractApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
//问题所在
TipsTransferService service= (TipsTransferServiceImpl) context.getBean("TipsTransferService");
System.out.println(service.test1());
报错信息:
Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy18 cannot be cast to com.djzh.core.service.impl.TipsTransferServiceImpl
spring有两种代理方式JDK动态代理和CGLIB动态代理。
Jdk 动态代理。具体有如下四步骤:
- 通过实现 InvocationHandler 接口创建自己的调用处理器;
- 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
- 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
- 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
GCLIB代理
cglib(Code Generation Library)是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。
cglib封装了asm,可以在运行期动态生成新的class。
cglib用于AOP,jdk中的proxy必须基于接口,cglib却没有这个限制。
原理区别:
jdk动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换
回归代码中,出问题的是有实现接口的,所以默认使用的是jdk动态代理,
但是TipsTransferServiceImpl和 context.getBean("TipsTransferService")是同级的,都算是实现了接口TipsTransferService,所以不能用来转换。而这里
可以使用cglib动态代理,因为它的实现方式不同于jdk动态代理。
在spring-aop.xml中可以配置强制使用cglib动态代理方式。以下链接中找到
http://blog.csdn.net/xlgen157387/article/details/51316814
主要是:proxy-target-class="true"<aop:aspectj-autoproxy proxy-target-class="true" ></aop:aspectj-autoproxy>
这样写。
还有一种解决方式就是把
TipsTransferService service= (TipsTransferServiceImpl) context.getBean("TipsTransferService");
代码中强制转换为接口即可,即
TipsTransferService service= (TipsTransferService) context.getBean("TipsTransferService");
通过这样的实验中,学到很多。
阅读全文
0 0
- GHGL项目总结-spring+mybatis多数据库源
- GHGL项目总结-mybatis
- GHGL项目总结-Myeclipse
- GHGL项目总结-Oracle
- GHGL项目总结-DB2
- GHGL项目总结-CA
- GHGL项目最后总结
- jeesite项目使用-多数据库配置【Spring mvc + Mybatis】
- GHGL项目总结-TIPS系统和银行拨付
- GHGL项目功能代码
- Spring SpringMVC Mybatis项目总结
- 项目总结:spring+mybatis整合
- mybatis + spring 多数据源跨库查询
- spring mybatis 多数据源
- spring Mybatis 多数据源
- spring(spring-boot) + mybatis多数据源
- SpringMVC+Mybatis框架的maven Spring boot项目,多数据源的实践
- 关于Spring-Mybatis项目多数据源配置应用的心得
- JAVA标准异常
- Java选择排序算法
- iOS WebView加载url缓存问题
- bugku 你必须让他停下
- 【spark】spark之shuffle调优
- GHGL项目总结-spring+mybatis多数据库源
- linux下使用 du查看某个文件或目录占用磁盘空间的大小
- 用Kotlin写第一个Android程序
- Python数据工具箱:数据库连接库
- mysql5.7修改密码报错 Unknown column 'password'
- Android拨打电话
- Elasticsearch 分布式存储原理
- Codeforces Round #426 (Div. 2) B. The Festive Evening
- 找朋友