Spring Abstractroutingdatasource enables Dynamic Data source switching

Source: Internet
Author: User

Using the Abstractroutingdatasource implementation provided by spring

Create the Abstractroutingdatasource implementation class, which is responsible for saving all data sources and switching data source policies:
public class Dynamicdatasource extends Abstractroutingdatasource {

@Override
Protected Object Determinecurrentlookupkey () {
Return Datasourcecontextholder.getdatasourcekey ( );
}
}
XML configuration data source and transaction:
<?xml version= "1.0" encoding= "UTF-8"?
<beans xmlns= "/http Www.springframework.org/schema/beans "
xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance "
xmlns:aop=" HTTP://WWW.SPRINGFRAMEWORK.ORG/SCHEMA/AOP "
xmlns:tx=" Http://www.springframework.org/schema/tx "
xsi: schemalocation= "
Http://www.springframework.org/schema/beans
Http://www.springframework.org/schema/beans /spring-beans.xsd
HTTP://WWW.SPRINGFRAMEWORK.ORG/SCHEMA/AOP
http://www.springframework.org/schema/aop/ Spring-aop.xsd
Http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/ Spring-tx.xsd ";

<bean id= "Dynamicdatasource" class= "Spring.dbs.DynamicDataSource" >
<property name= "Defaulttargetdatasource" ref= "Primarydatasource"/>
<property name= "Targetdatasources" >
<map>
<entry key= "Primarydatasource" value-ref= "Primarydatasource" ></entry>
<entry key= "Secondarydatasource" value-ref= "Secondarydatasource" ></entry>
<entry key= "Thirdlydatasource" value-ref= "Thirdlydatasource" ></entry>
</map>
</property>
</bean>

<bean id= "TransactionManager" class= "Org.springframework.jdbc.datasource.DataSourceTransactionManager" >
<property name= "DataSource" ref= "Dynamicdatasource"/>
</bean>

<tx:advice id= "Txadvice" transaction-manager= "TransactionManager" >
<tx:attributes>
<tx:method name= "batch*" propagation= "REQUIRED"/>
<tx:method name= "add*" propagation= "REQUIRED"/>
<tx:method name= "insert*" propagation= "REQUIRED"/>
<tx:method name= "persist*" propagation= "REQUIRED"/>
<tx:method name= "delete*" propagation= "REQUIRED"/>
<tx:method name= "remove*" propagation= "REQUIRED"/>
<tx:method name= "merge*" propagation= "REQUIRED"/>
<tx:method name= "update*" propagation= "REQUIRED"/>
<tx:method name= "select*" read-only= "true" propagation= "SUPPORTS"/>
<tx:method name= "query*" read-only= "true" propagation= "SUPPORTS"/>
<tx:method name= "get*" read-only= "true" propagation= "SUPPORTS"/>
<tx:method name= "load*" read-only= "true" propagation= "SUPPORTS"/>
<tx:method name= "find*" read-only= "true" propagation= "SUPPORTS"/>
<tx:method name= "*" read-only= "true" propagation= "SUPPORTS"/>
</tx:attributes>
</tx:advice>

<aop:config>
<aop:pointcut id= "txpointcut" expression= "Execution (* spring.service). *(..))" />
<aop:advisor pointcut-ref= "Txpointcut" advice-ref= "Txadvice"/>
</aop:config>
</beans>

Look at the Datasourcecontextholder implementation, which is responsible for handling key switching data source policies, using threadlocal to ensure thread isolation:
public class Datasourcecontextholder {

private static final threadlocal<string> Datasource_key = new threadlocal<> ();

/**
* Set Datasourcekey
*
* @param datasourcekey
*/
public static void Setdatasourcekey (String datasourcekey) {
Datasource_key.set (Datasourcekey);
}

/**
* Get Datasourcekey
*
* @return
*/
public static String Getdatasourcekey () {
return Datasource_key.get ();
}

/**
* Delete Datasourcekey
*/
public static void Cleardatasourcekey () {
Datasource_key.remove ();
}
}

Implement policies using AOP to dynamically switch data sources:
@Component
@Aspect
public class Datasourcehandler {

private static final Logger Logger = Loggerfactory.getlogger (Datasourcehandler.class);

private static final string[] datasources = new string[]{"Primarydatasource", "Secondarydatasource", "Thirdlydatasource "};

① @Pointcut ("Execution (* spring.service). *(..))")
public void Datasourcepoint () {
}

@Around ("Datasourcepoint ()")
Public Object handler (Proceedingjoinpoint point) throws Throwable {
Logger.info ("Begin get DataSource ...");
object[] args = Point.getargs ();
if (null! = args && args.length > 0) {
②string key = String.valueof (Args[0]);
//Deposit key
③dataso Urcecontextholder.setdatasourcekey (GetKey (key));
}
Object result = Point.proceed ();
//Clear Key
④datasourcecontextholder.cleardatasourcekey ();
Logger.info ("End Get DataSource ...");
return result;
}

/**
* Get the Key method
*
* @param key
* @return
*/
Private String GetKey (String key) {
Logger.info ( "This key is: [" + Key + "]!");
CRC32 CRC = New CRC32 ();
Crc.update (Key.getbytes (standardcharsets.utf_8));
Long result = Crc.getvalue ();
Logger.info ("This key ' s CRC32 is: [" + result + "]!");
int index = (int) (result% 3);
Logger.info ("This key ' s module is: [" + Index + "]!");
int len = datasources.length;
if (Index > (len-1)) {
index = len-1;
}
Logger.info ("This key ' s result module is: [" + Index + "]!");
String datasourcekey = Datasources[index];
Logger.info ("This DataSource key is: [" + Datasourcekey + "]!");
return datasourcekey;
}
}
① the method execution policy under all service packages,
②demo uses the first parameter as key by default,
③ uses CRC32 modulo to get the data source key, Save to DataSourceContextHolder.ThreadLocal.DATASOURCE_KEY to ensure that different thread policies are correct;
④ the business logic after processing, clear KEY;


Using JdbcTemplate, configure the following:
@Configuration
public class Jdbctemplatebean {

@Autowired
@Qualifier ("Dynamicdatasource")
Private DataSource Dynamicdatasource;

@Bean (name = "Dynamicjdbctemplate")
@Qualifier ("Dynamicjdbctemplate")
Public Namedparameterjdbctemplate primaryjdbctemplate () {
return new Namedparameterjdbctemplate (Dynamicdatasource);
}
}

A problem was found during use, when the transaction was configured to Propagation= "REQUIRED", because the AOP order problem resulted in the discovery of a data source to open a transaction, followed by a data source switching strategy, using <aop:advisor order= "2"/> The property is configured with a transaction order of 2 and uses the Org.springframework.core.Ordered interface to set the policy execution order to 1, ensuring that policy execution is preceded by the search for a data source, as follows:
Transaction plane configuration:
<aop:config>
<aop:pointcut id= "txpointcut" expression= "Execution (* spring.service). *(..))" />
<aop:advisor pointcut-ref= "Txpointcut" advice-ref= "Txadvice" order= "2"/>
</aop:config>
Policy execution Facets:
@Component
@Aspect
public class Datasourcehandler implements Ordered {

@Pointcut ("Execution (* spring.service). *(..))")
public void Datasourcepoint () {
}

@Around ("Datasourcepoint ()")
Public Object Handler (Proceedingjoinpoint point) throws Throwable {
Policy implementation
}


@Override
public int GetOrder () {
return 1;
}
}

Spring Abstractroutingdatasource enables Dynamic Data source switching

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.