您的位置:首页 > 编程语言 > Java开发

spring多数据源配置+aop注解方式属性注入

2017-08-07 15:34 302 查看
本文将介绍spring中多个数据源的配置,同时使用注解的方式切换选择数据源。

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 versionspring versionaspectjrt version and aspectjweaver version
1.63.0 +aspectjrt-1.6.2  and aspectjweaver-1.6.2
1.73.0 +aspectjrt-1.7.3 and aspectjweaver-1.7.3
我用的是1.7版本的jdk所以在pom.xml中需配置

<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即可
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  JavaEE spring aop
相关文章推荐