Spring Multi-data source, dynamic Data stream code parsing

Source: Internet
Author: User

All connection pools in Java are implemented in accordance with the specifications of the DataSource interface, the connection can be obtained by getconnection () to get the connection without the relationship between the underlying database connection pool.

1 public interface DataSource extends Commondatasource, Wrapper {
2
3 Connection getconnection () throws SQLException;
4
5 Connection getconnection (string Username, string password) throws SQLException;
6}
In most systems we only need one data source, and now the web system is usually the cornerstone of spring. Whether you're an XML configuration, a JavaBean configuration, or a yml,properties configuration file configuration, the core is to inject a data source into the management of spring.

In some systems we may face a number of situations, the connection of multiple tables, master and slave, and even a number of different libraries and so on, the core requirement is that we may need to configure multiple connection pools.

In MyBatis systems we use multiple data sources to configure multiple datasource,sqlsessionfactory,sqlsessiontemplate and then manage them separately in XML and mapper.
This scheme is sufficient for small systems, and the author thinks it is more suitable for many different databases.

Back to the point, in spring from the 2.0.1 version of the default provides Abstractroutingdatasource, we inherit it to implement related methods, all the required data sources can be dynamically switched data source. We can look at the core method of the source code.

Public abstract class Abstractroutingdatasource extends Abstractdatasource implements Initializingbean {
?
Set up all the data sources
Private Map<object, object> targetdatasources;
Sets the default data source and returns the default data source when no relevant data source is found
Private Object Defaulttargetdatasource;
Fast failure, negligible
Private Boolean lenientfallback = true;
Jndi-related, can be ignored
Private Datasourcelookup datasourcelookup = new Jndidatasourcelookup ();
After parsing all the data sources, the core
Private Map<object, datasource> resolveddatasources;
After parsing the default data source, the core
Private DataSource Resolveddefaultdatasource;
?
To set the correlation parameter method
public void Settargetdatasources (Map<object, object> targetdatasources) {
This.targetdatasources = targetdatasources;
}
public void Setdefaulttargetdatasource (Object defaulttargetdatasource) {
This.defaulttargetdatasource = Defaulttargetdatasource;
}
public void Setlenientfallback (Boolean lenientfallback) {
This.lenientfallback = Lenientfallback;
}
public void Setdatasourcelookup (Datasourcelookup datasourcelookup) {
This.datasourcelookup = (Datasourcelookup! = null? Datasourcelookup:new jndidatasourcelookup ()); br/>}
?
@Override
Detect whether to set all data sources
if (this.targetdatasources = = null) {
throw new IllegalArgumentException ("Property ' targetdatasources ' is required");
}
Parsing all data sources is generally useless, mostly if map<object, the value of Object> targetdatasources is a string that is looked up from the Jndi data source
This.resolveddatasources = new Hashmap<object, datasource> (This.targetDataSources.size ());
For (Map.entry<object, object> entry:this.targetDataSources.entrySet ()) {
Object LookupKey = Resolvespecifiedlookupkey (Entry.getkey ());
DataSource DataSource = Resolvespecifieddatasource (Entry.getvalue ());
This.resolvedDataSources.put (LookupKey, DataSource);
}
Parse the default data source as Ditto
if (This.defaulttargetdatasource! = null) {
This.resolveddefaultdatasource = Resolvespecifieddatasource (this.defaulttargetdatasource); br/>}
}
?
@Override
Core, get the data source find the current connection pool and get the data source first
Return Determinetargetdatasource (). getconnection (); br/>}
?
@Override
Return Determinetargetdatasource (). getconnection (username, password);
}
?
Protected DataSource Determinetargetdatasource () {
Call Determinecurrentlookupkey, then go to Resolveddefaultdatasource to find it, return the corresponding data source, not return the default data source
Assert.notnull (this.resolveddatasources, "DataSource router not initialized");
Object LookupKey = Determinecurrentlookupkey ();
DataSource DataSource = This.resolvedDataSources.get (LookupKey);
if (DataSource = = null && (This.lenientfallback | | lookupkey = = NULL)) {
DataSource = This.resolveddefaultdatasource;
}
if (DataSource = = null) {
throw new IllegalStateException ("cannot determine target DataSource for lookup key [" + LookupKey + "]");
}
return dataSource;
}

//而determineCurrentLookupKey需要我们自己去实现。//通常需要结合Aop和ThreadLocal。我们Aop从注解上获取当前用户用户所希望的数据源,然后设置到当前线程。在determineCurrentLookupKey再从当前线程拿出来返回给determineTargetDataSource由其决定最终数据源protected abstract Object determineCurrentLookupKey();

?
}

Advantages: Convenient configuration, convenient use. Cons: The default implementation has some limitations, and most people are enough to use it. If you have more complex usage scenarios, multi-Library data sources, grouped data sources, multi-master and many more, more complex scenarios can be tried

A springboot-based quick-integration launcher for multiple data sources.

A standard master-slave configuration is as follows, which can be used with the introduction of related configurations. More ways to view related documents.

Spring
DataSource
Dynamic
Primary:master #设置默认的数据源或者数据源组, the default value is master, if you master the main library by default the name is master does not define this item.
DataSource
Master
Username:root
password:123456
Driver-class-name:com.mysql.jdbc.driver
Url:jdbc:mysql://47.100.20.186:3306/dynamic?characterencoding=utf8&usessl=false
Slave_1:
Username:root
password:123456
Driver-class-name:com.mysql.jdbc.driver
Url:jdbc:mysql://47.100.20.186:3307/dynamic?characterencoding=utf8&usessl=false
Slave_2:
Username:root
password:123456
Driver-class-name:com.mysql.jdbc.driver
Url:jdbc:mysql://47.100.20.186:3308/dynamic?characterencoding=utf8&usessl=false

Realize the core source code as follows

public class Dynamicroutingdatasource extends Abstractroutingdatasource {

/** * All Libraries */private map&lt; String, datasource&gt; datasourcemap;/** * Packet Database */private map&lt; String, dynamicgroupdatasource&gt; Groupdatasources = new hashmap&lt;&gt; (); @Setterprivate Dynamicdatasourceprovider Dynamicdatasourceprovider ; @Setterprivate class&lt;? Extends dynamicdatasourcestrategy&gt; dynamicdatasourcestrategyclass;/** * Default data source name, default master, can be a group data source name, can be a single data source name */@Setterprivate String primary;@ overrideprotected Object Determinecurrentlookupkey () {return Dynamicdatasourcecontextholder.getdatasourcelookupkey ();}    @Overrideprotected DataSource Determinetargetdatasource () {String lookupkey = (String) determinecurrentlookupkey ();        if (Groupdatasources.containskey (LookupKey)) {Log.debug ("return data source from {} Group data source", LookupKey);    Return Groupdatasources.get (LookupKey). Determinedatasource ();        } else if (Datasourcemap.containskey (LookupKey)) {Log.debug ("return data source from {} Single data source", LookupKey);    Return Datasourcemap.get (LookupKey); } LoG.debug ("Return data from the default data source"); return Groupdatasources.containskey (primary)? Groupdatasources.get (LookupKey). Determinedatasource (): Datasourcemap.get (primary);}    @Overridepublic void Afterpropertiesset () {this.datasourcemap = Dynamicdatasourceprovider.loaddatasources ();    Log.debug ("co-loading {} Data Sources", datasourcemap.size ()); Packet data source for (map.entry&lt; String, datasource&gt;        DsItem:dataSourceMap.entrySet ()) {String dsname = Dsitem.getkey ();            if (Dsname.contains ("_")) {string[] Groupds = Dsname.split ("_");            String groupName = groupds[0];            DataSource DataSource = Dsitem.getvalue ();            if (Groupdatasources.containskey (GroupName)) {Groupdatasources.get (groupName). AddDatasource (DataSource); } else {try {dynamicgroupdatasource groupdatasource = new Dynamicgroupdataso                    Urce (GroupName, Dynamicdatasourcestrategyclass.newinstance ()); Groupdatasource.adddaTasource (DataSource);                Groupdatasources.put (GroupName, Groupdatasource);                } catch (Exception e) {e.printstacktrace (); }}}}//Detect group data source Settings iterator&lt; map.entry&lt; String, dynamicgroupdatasource&gt;&gt;    Groupiterator = Groupdatasources.entryset (). iterator (); while (Groupiterator.hasnext ()) {map.entry&lt; String, dynamicgroupdatasource&gt;        item = Groupiterator.next ();        Log.debug (there are {} data sources under Group {}, Item.getkey (), Item.getvalue (). Size ());            if (Item.getvalue (). Size () = = 1) {Log.warn ("Be careful not to set up a group with only one data source, {} Group will be removed", item.getkey ());        Groupiterator.remove (); }}//detect default data source setting if (Groupdatasources.containskey (primary)) {Log.debug ("The current default data source is a group data source, the group name is {}, and there are {} data sources"    , primary, Groupdatasources.size ());    } else if (Datasourcemap.containskey (primary)) {Log.debug ("The current default data source is a single data source, the data source name is {}", primary);   } else {     throw new RuntimeException ("Please check primary default database settings, not currently found" + primary + "data source"); }}

}

Spring Multi-data source, dynamic Data stream code parsing

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.