首页 > 技术文章 > Spring aop读写分离

jiangxiaoyaoblog 原文

一、采用读写分离技术的目标

       随着网站的业务不断扩展,数据不断增加,用户越来越多,数据库的压力也就越来越大,采用传统的方式,比如:数据库或者SQL的优化基本已达不到要求,这个时候可以采用读写分离的策略来改变现状。采用读写分离技术能够有效减轻Master库的压力,又可以把用户查询数据的请求分发到不同的Slave库,从而保证系统的健壮性。

二、常用的两种方式

    1、定义两个数据库链接,一个是masterDataSource,另个是slaveDataSource,更新数据时读取masterDataSource,查询是读取slaveDataSource。

     2、动态数据源切换,在程序运行时,把数据源动态织如入程序中,从而选择主库还是从库。主要技术采用annotation,Spring AOP,反射,接下来详细介绍该种方法。

三、动态数据源切换实现读写分离

 1,定义DataSource注解

@Retention(RetentionPolicy.RUNTIME)  

@Target(ElementType.METHOD)

public @interface DataSource {

 String value(); 

}

2,继承抽象类AbstractRoutingDataSource来实现DynamicDataSource方法 

public class DynamicDataSource extends AbstractRoutingDataSource{ 

 public static final Logger logger = Logger.getLogger(DynamicDataSource.class.toString()); 

 @Override

    protected Object determineCurrentLookupKey() {

         return DynamicDataSourceHolder.getDataSource();

    }

}

3,定义DynamicDataSourceHolder方法

 public class DynamicDataSourceHolder {

  private static final ThreadLocal<String> holder = new ThreadLocal<String>();

     public static void setDataSource(String name) {

         holder.set(name);

     }

     public static String getDataSource() {

         return holder.get();

     }  

}

4,定义DataSourceAspect类,在程序运行时动态切换数据源

public class DataSourceAspect {  

    public void before(JoinPoint point){  

        Object target = point.getTarget();   

        String method = point.getSignature().getName();   

        Class<?>[] classz = target.getClass().getInterfaces();  

        Class<?>[] parameterTypes = ((MethodSignature)point.getSignature()).getParameterTypes();  

        try{  

            Method m = classz[0].getMethod(method, parameterTypes);  

            if(m != null && m.isAnnotationPresent(DataSource.class)){  

                DataSource date = m.getAnnotation(DataSource.class);  

                DynamicDataSourceHolder.setDataSource(date.value());  

            }  

            else {

                // 默认master

                DynamicDataSourceHolder.setDataSource("master");

            }

        }catch(Exception e){               

        }  

    }  

}

5,applicationContext-dataSource.xml配置

  分别定义主从数据源后,再添加选择数据源的bean

<bean id="dataSource" class="****">

 <property name="targetDataSources">

 <map key-type="java.lang.String">

 <entry key="master" value-ref="masterDataSource"/>

 <entry key="slave" value-ref="slaveDataSource"/>

   </map>

 </property>

 <property name="defaultTargetDataSource" ref="masterDataSource"/>

 </bean>

增加aop配置

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>      <bean id="manyDataSourceAspect" class="****.DataSourceAspect" />  

    <aop:config>  

        <aop:aspect id="c" ref="manyDataSourceAspect">  

            <aop:before method="before" pointcut="execution(* *****.data.dao.*.*(..))"></aop:before>  

        </aop:aspect>  

    </aop:config>  

6,DAO层定义方法的数据源

@DataSource(value="slave")

 public ImUser findById(int id);

推荐阅读