spring多数据源配置+aop注解方式属性注入
2017-08-07 15:34
302 查看
本文将介绍spring中多个数据源的配置,同时使用注解的方式切换选择数据源。
spring的其他配置不再细说,只说数据源的相关配置。
参考多篇博文实践整理,不在一一查找出处,如有侵权请及时联系
====================================
1.修改spring配置
1.1加入数据源
2.1DynamicDataSource.java
在相关的dao层加上数据源的切换即可,如:
4.1定义注解
在spring中使用aop除了导入相关jar包,别忘了一下代码
4.3编写aop的处理类
从4.2开始,也可以使用注解的方式配置aop,但是存在一些问题,在这里提一下,不推荐
4.2配置aop
在xml配置文件中加入
使用方法不变
说说这种方式碰到的问题及解决方式:
1. 0 can't find referenced pointcut
这是开发环境jdk版本导致的,见下表
我用的是1.7版本的jdk所以在pom.xml中需配置
从Spring3.2以后,spring框架本身不在需要cglib这个jar包了,因为cjlib.jar已经被spring项目的jar包集成进去。为了防止项目中其他对cglib版本依赖不一样的冲突。
所以切换spring版本为4.2.5.RELEASE即可
spring的其他配置不再细说,只说数据源的相关配置。
参考多篇博文实践整理,不在一一查找出处,如有侵权请及时联系
====================================
1.修改spring配置
1.1加入数据源
...... <!-- 配置数据源 使用的是Druid数据源 --> <bean id="dataSourceOne" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> <!-- 配置监控统计拦截的filters,去掉后监控界面sql无法统计 --> <property name="filters" value="stat" /> </bean> <bean id="dataSourceTwo" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driver2}" /> <property name="url" value="${jdbc.url2}"></property> <property name="username" value="${jdbc.username2}"></property> <property name="password" value="${jdbc.password2}"></property> <!-- 配置监控统计拦截的filters,去掉后监控界面sql无法统计 --> <property name="filters" value="stat" /> </bean> ......1.2用统一的类处理,切换数据源,指定如果不设置,默认使用第一个数据源
<bean id="dynamicDataSource" class="com.best.core.DynamicDataSource"> <property name="targetDataSources"> <map key-type="java.lang.String"> <entry value-ref="dataSourceOne" key="dataSourceOne"></entry> <entry value-ref="dataSourceTwo" key="dataSourceTwo"></entry> </map> </property> <property name="defaultTargetDataSource" ref="dataSourceOne"> </property> </bean>1.3在sqlsession中引用
<!-- myBatis文件 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dynamicDataSource" /> <property name="mapperLocations" value="classpath:sqlmap/*.xml" /> <property name="plugins"> <array> <bean class="com.github.pagehelper.PageInterceptor"> <!-- 这里的几个配置主要演示如何使用,如果不理解,一定要去掉下面的配置 --> <property name="properties"> <value> helperDialect=mysql reasonable=true supportMethodsArguments=true params=count=countSql </value> </property> </bean> </array> </property> </bean>2.数据源控制类的编写
2.1DynamicDataSource.java
public class DynamicDataSource extends AbstractRoutingDataSource{ @Override protected Object determineCurrentLookupKey() { return DynamicDataSourceHolder.getDataSource(); } }2.2DynamicDataSourceHolder.java
public class DynamicDataSourceHolder { /** * 注意:数据源标识保存在线程变量中,避免多线程操作数据源时互相干扰 */ private static final ThreadLocal<String> THREAD_DATA_SOURCE = new ThreadLocal<String>(); public static String getDataSource() { return THREAD_DATA_SOURCE.get(); } public static void setDataSource(String dataSource) { THREAD_DATA_SOURCE.set(dataSource); } public static void clearDataSource() { THREAD_DATA_SOURCE.remove(); } }3.调用
在相关的dao层加上数据源的切换即可,如:
DynamicDataSourceHolder.setDataSource("dataSourceTwo"); List<User> list = userMapper.selectAll();4.使用spring的aop实现注解选择数据源
4.1定义注解
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface DataSource { String value(); }4.2配置aop(基于xml配置文件的方式)
<bean id="dataSourceAspect" class="com.best.core.DataSourceAspect" /> <aop:config> <aop:aspect ref="dataSourceAspect"> <!-- 拦截所有mapper方法 --> <aop:pointcut id="dataSourcePointcut" expression="execution(* com.best.mapper.*.*(..))"/> <aop:before pointcut-ref="dataSourcePointcut" method="intercept" /> </aop:aspect> </aop:config>
在spring中使用aop除了导入相关jar包,别忘了一下代码
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd ">
4.3编写aop的处理类
public class DataSourceAspect { /** * 拦截目标方法,获取由@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(); DataSource source =null; // 默认使用类型注解 if (clazz.isAnnotationPresent(DataSource.class)) { source = clazz.getAnnotation(DataSource.class); DynamicDataSourceHolder.setDataSource(source.value()); } // 方法注解可以覆盖类型注解 Method m = clazz.getMethod(method.getName(), types); if (m != null && m.isAnnotationPresent(DataSource.class)) { source = m.getAnnotation(DataSource.class); DynamicDataSourceHolder.setDataSource(source.value()); } } catch (Exception e) { System.out.println(clazz + ":" + e.getMessage()); } } }4.4注解的使用,可以在类或者方法上声明,取决于DataSourceAspect类的编写
@DataSource("dataSourceTwo") public interface UserMapper extends BaseMapper<User, Integer>{ User selectByMobile(String mobile); int updateByMobileSelective(User user); List<User> selectStudents(); }以上是基于xml文件的aop配置
从4.2开始,也可以使用注解的方式配置aop,但是存在一些问题,在这里提一下,不推荐
4.2配置aop
在xml配置文件中加入
<!-- 激活自动代理功能 --> <aop:aspectj-autoproxy proxy-target-class="true"/>4.3编写aop处理类
@Component @Aspect //@EnableAspectJAutoProxy(proxyTargetClass = true) //若已经在xml中配置此处可以省略 public class DataSourceAspect { //配置切入点,该方法无方法体,主要为方便同类中其他方法使用此处配置的切入点 @Pointcut("execution(* com.best.mapper.*.*(..))") public void aspect(){} /** * 拦截目标方法,获取由@DataSource指定的数据源标识,设置到线程存储中以便切换数据源 * * @param point * @throws Exception */ @Before("aspect()") 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(); DataSource source =null; // 默认使用类型注解 if (clazz.isAnnotationPresent(DataSource.class)) { source = clazz.getAnnotation(DataSource.class); DynamicDataSourceHolder.setDataSource(source.value()); } // 方法注解可以覆盖类型注解 Method m = clazz.getMethod(method.getName(), types); if (m != null && m.isAnnotationPresent(DataSource.class)) { source = m.getAnnotation(DataSource.class); DynamicDataSourceHolder.setDataSource(source.value()); } } catch (Exception e) { System.out.println(clazz + ":" + e.getMessage()); } } }
使用方法不变
说说这种方式碰到的问题及解决方式:
1. 0 can't find referenced pointcut
这是开发环境jdk版本导致的,见下表
jdk version | spring version | aspectjrt version and aspectjweaver version |
1.6 | 3.0 + | aspectjrt-1.6.2 and aspectjweaver-1.6.2 |
1.7 | 3.0 + | aspectjrt-1.7.3 and aspectjweaver-1.7.3 |
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.7.3</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.7.3</version> </dependency>2.Cannot subclass final class class com.sun.proxy.$Proxy16
从Spring3.2以后,spring框架本身不在需要cglib这个jar包了,因为cjlib.jar已经被spring项目的jar包集成进去。为了防止项目中其他对cglib版本依赖不一样的冲突。
所以切换spring版本为4.2.5.RELEASE即可
相关文章推荐
- ######【spring属性注入(Ioc的DI)总结】:注解方式属性注入,属性名任意.=for理解:Aop注入代理对象时,注入被增强类对象时,属性名为proxy(自定义)。
- Spring通过@Value注解注入属性的几种方式
- spring学习(五)—通过注解方式创建对象和注入属性
- Spring如何通过注解方式注入静态属性
- Web框架梳理:第四章:Spring学习入门、Spring属性注入、AOP编程、注解开发
- spring-04 之IOC 属性注入(注解方式 附代码)
- 详解Spring通过@Value注解注入属性的几种方式
- Spring AOP注解通过@Autowired,@Resource,@Qualifier,@PostConstruct,@PreDestroy注入属性的配置文件详解
- Spring通过@Value注解注入属性的几种方式
- Spring AOP注解通过@Autowired,@Resource,@Qualifier,@PostConstruct,@PreDestroy注入属性的配置文件详解
- Spring AOP注解通过@Autowired,@Resource,@Qualifier,@PostConstruct,@PreDestroy注入属性的配置文件详解
- Spring AOP注解通过@Autowired,@Resource,@Qualifier,@PostConstruct,@PreDestroy注入属性的配置文件详解
- Spring依赖注入方式_属性setter方法注入_构造器注入_注解注入
- spring详解:使用注解方式注入属性
- ######Spring第5天ssh整合(注解版)难理解知识点:【自定义 方法加注解的方式】给dao注入sessionFactory属性+【搞清@Autowared和@Resource含义】
- Spring使用注解的方式注入属性时的xml文件配置
- Spring AOP注解通过@Autowired,@Resource,@Qualifier,@PostConstruct,@PreDestroy注入属性的配置文件详解
- Spring AOP注解通过@Autowired,@Resource,@Qualifier,@PostConstruct,@PreDestroy注入属性的配置文件详解
- Spring AOP注解通过@Autowired,@Resource(J2EE提供),@Qualifier,@PostConstruct,@PreDestroy注入属性的配置文件详解
- Spring AOP注解通过@Autowired,@Resource,@Qualifier,@PostConstruct,@PreDestroy注入属性的配置文件详解