当前位置: 移动技术网 > IT编程>开发语言>Java > 详解使用spring aop实现业务层mysql 读写分离

详解使用spring aop实现业务层mysql 读写分离

2019年07月22日  | 移动技术网IT编程  | 我要评论
spring aop , mysql 主从配置 实现读写分离,接下来把自己的配置过程,以及遇到的问题记录下来,方便下次操作,也希望给一些朋友带来帮助。 1.使用spr

spring aop , mysql 主从配置 实现读写分离,接下来把自己的配置过程,以及遇到的问题记录下来,方便下次操作,也希望给一些朋友带来帮助。

1.使用spring aop 拦截机制现数据源的动态选取。

import java.lang.annotation.elementtype; 
import java.lang.annotation.target; 
import java.lang.annotation.retention; 
import java.lang.annotation.retentionpolicy; 
/** 
 * runtime 
 * 编译器将把注释记录在类文件中,在运行时 vm 将保留注释,因此可以反射性地读取。 
 * @author yangguang 
 * 
 */ 
@retention(retentionpolicy.runtime) 
@target(elementtype.method) 
public @interface datasource { 
  string value(); 
} 

3.利用spring的abstractroutingdatasource解决多数据源的问题

import org.springframework.jdbc.datasource.lookup.abstractroutingdatasource; 
 
 public class choosedatasource extends abstractroutingdatasource { 
 
   @override 
   protected object determinecurrentlookupkey() { 
     return handledatasource.getdatasource(); 
   } 
    
 } 

4.利用threadlocal解决线程安全问题

public class handledatasource { 
  public static final threadlocal<string> holder = new threadlocal<string>(); 
  public static void putdatasource(string datasource) { 
    holder.set(datasource); 
  } 
   
  public static string getdatasource() { 
    return holder.get(); 
  }   
} 

5.定义一个数据源切面类,通过aop访问,在spring配置文件中配置了,所以没有使用aop注解。

import java.lang.reflect.method; 
import org.aspectj.lang.joinpoint; 
import org.aspectj.lang.annotation.aspect; 
import org.aspectj.lang.annotation.before; 
import org.aspectj.lang.annotation.pointcut; 
import org.aspectj.lang.reflect.methodsignature; 
import org.springframework.stereotype.component; 
//@aspect 
//@component 
public class datasourceaspect { 
  //@pointcut("execution(* com.apc.cms.service.*.*(..))")  
  public void pointcut(){};  
   
 // @before(value = "pointcut()") 
   public void before(joinpoint point) 
    { 
      object target = point.gettarget(); 
      system.out.println(target.tostring()); 
      string method = point.getsignature().getname(); 
      system.out.println(method); 
      class<?>[] classz = target.getclass().getinterfaces(); 
      class<?>[] parametertypes = ((methodsignature) point.getsignature()) 
          .getmethod().getparametertypes(); 
      try { 
        method m = classz[0].getmethod(method, parametertypes); 
        system.out.println(m.getname()); 
        if (m != null && m.isannotationpresent(datasource.class)) { 
          datasource data = m.getannotation(datasource.class); 
          handledatasource.putdatasource(data.value()); 
        } 
         
      } catch (exception e) { 
        e.printstacktrace(); 
      } 
    } 
} 

6.配置applicationcontext.xml

<!-- 主库数据源 --> 
 <bean id="writedatasource" class="com.jolbox.bonecp.bonecpdatasource" destroy-method="close"> 
  <property name="driverclass" value="com.mysql.jdbc.driver"/> 
  <property name="jdbcurl" value="jdbc:mysql://172.22.14.6:3306/cpp?autoreconnect=true"/> 
  <property name="username" value="root"/> 
  <property name="password" value="root"/> 
  <property name="partitioncount" value="4"/> 
  <property name="releasehelperthreads" value="3"/> 
  <property name="acquireincrement" value="2"/> 
  <property name="maxconnectionsperpartition" value="40"/> 
  <property name="minconnectionsperpartition" value="20"/> 
  <property name="idlemaxageinseconds" value="60"/> 
  <property name="idleconnectiontestperiodinseconds" value="60"/> 
  <property name="poolavailabilitythreshold" value="5"/> 
</bean> 
 
<!-- 从库数据源 --> 
<bean id="readdatasource" class="com.jolbox.bonecp.bonecpdatasource" destroy-method="close"> 
  <property name="driverclass" value="com.mysql.jdbc.driver"/> 
  <property name="jdbcurl" value="jdbc:mysql://172.22.14.7:3306/cpp?autoreconnect=true"/> 
  <property name="username" value="root"/> 
  <property name="password" value="root"/> 
  <property name="partitioncount" value="4"/> 
  <property name="releasehelperthreads" value="3"/> 
  <property name="acquireincrement" value="2"/> 
  <property name="maxconnectionsperpartition" value="40"/> 
  <property name="minconnectionsperpartition" value="20"/> 
  <property name="idlemaxageinseconds" value="60"/> 
  <property name="idleconnectiontestperiodinseconds" value="60"/> 
  <property name="poolavailabilitythreshold" value="5"/> 
</bean> 
 
<!-- transaction manager, 事务管理 --> 
<bean id="transactionmanager" class="org.springframework.jdbc.datasource.datasourcetransactionmanager"> 
  <property name="datasource" ref="datasource" /> 
</bean> 
 
 
<!-- 注解自动载入 --> 
<context:annotation-config /> 
 
<!--enale component scanning (beware that this does not enable mapper scanning!)--> 
<context:component-scan base-package="com.apc.cms.persistence.rdbms" /> 
<context:component-scan base-package="com.apc.cms.service"> 
 <context:include-filter type="annotation"  
    expression="org.springframework.stereotype.component" />  
</context:component-scan>  
 
<context:component-scan base-package="com.apc.cms.auth" /> 
 
<!-- enable transaction demarcation with annotations --> 
<tx:annotation-driven /> 
 
 
<!-- define the sqlsessionfactory --> 
<bean id="sqlsessionfactory" class="org.mybatis.spring.sqlsessionfactorybean"> 
  <property name="datasource" ref="datasource" /> 
  <property name="typealiasespackage" value="com.apc.cms.model.domain" /> 
</bean> 
 
<!-- scan for mappers and let them be autowired --> 
<bean class="org.mybatis.spring.mapper.mapperscannerconfigurer"> 
  <property name="basepackage" value="com.apc.cms.persistence" /> 
  <property name="sqlsessionfactory" ref="sqlsessionfactory" /> 
</bean> 
 
<bean id="datasource" class="com.apc.cms.utils.choosedatasource"> 
  <property name="targetdatasources">  
     <map key-type="java.lang.string">  
       <!-- write --> 
       <entry key="write" value-ref="writedatasource"/>  
       <!-- read --> 
       <entry key="read" value-ref="readdatasource"/>  
     </map>  
      
  </property>  
  <property name="defaulttargetdatasource" ref="writedatasource"/>  
</bean> 
  
<!-- 激活自动代理功能 --> 
<aop:aspectj-autoproxy proxy-target-class="true"/> 
 
<!-- 配置数据库注解aop --> 
<bean id="datasourceaspect" class="com.apc.cms.utils.datasourceaspect" /> 
<aop:config> 
  <aop:aspect id="c" ref="datasourceaspect"> 
    <aop:pointcut id="tx" expression="execution(* com.apc.cms.service..*.*(..))"/> 
    <aop:before pointcut-ref="tx" method="before"/> 
  </aop:aspect> 
</aop:config> 
<!-- 配置数据库注解aop --> 

7.使用注解,动态选择数据源,分别走读库和写库。

@datasource("write") 
public void update(user user) { 
  usermapper.update(user); 
} 
 
@datasource("read") 
public document getdocbyid(long id) { 
  return documentmapper.getbyid(id); 
} 

测试写操作:可以通过应用修改数据,修改主库数据,发现从库的数据被同步更新了,所以定义的write操作都是走的写库

测试读操作:  后台修改从库数据,查看主库的数据没有被修改,在应用页面中刷新,发现读的是从库的数据,说明读写分离ok。

遇到的问题总结:

问题1:项目是maven工程,用到了spring aop机制,除了spring的核心jar包以为,还需要用到的jar包有aspectj.jar,aspectjweaver.jar,aopalliance.jar查看项目中的pom,发现缺少依赖包,由于本地仓库没有这些jar,查找可以提供下载jar包的maven中央库库,配置到maven中,自动更新:

<repository> 
   <id>nexus</id> 
   <name>nexus</name> 
   <url>http://repository.sonatype.org/content/groups/public/</url> 
   <layout>default</layout> 
 </repository> 

配置项目依赖的jar,主要是缺少这两个。

  <dependency> 
    <groupid>aspectj</groupid> 
    <artifactid>aspectjrt</artifactid> 
    <version>1.5.4</version> 
</dependency> 
<dependency> 
    <groupid>aspectj</groupid> 
    <artifactid>aspectjweaver</artifactid> 
    <version>1.5.4</version> 
lt;/dependency> 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网