Spring Multi-data source, dynamic Data stream code parsing

Source: Internet
Author: User
Tags aop

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 {23   throws  SQLException; 4 5   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. Refer to 61202084 this blog for details.

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 all 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, can ignore 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.targetdatasource    s = targetdatasources; } public void Setdefaulttargetdatasource (Object defaulttargetdatasource) {This.defaulttargetdatasource = Defaul    Ttargetdatasource;    The public void Setlenientfallback (Boolean lenientfallback) {this.lenientfallback = Lenientfallback; } public void Setdatasourcelookup (Datasourcelookup datasourcelookup) {this.datasourcelookup = (Datasourcelookup! = null? datasourcelookup:new Jnd    Idatasourcelookup ());    }?            @Override public void Afterpropertiesset () {//detects 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, object> Targetdatasources's value is string, it is looked up from the Jndi data source This.resolvedda        Tasources = new Hashmap<object, datasource> (This.targetDataSources.size ()); For (Map.entry<object, object> entry:this.targetDataSources.entrySet ()) {Object LookupKey = Resolvespe            Cifiedlookupkey (Entry.getkey ());            DataSource DataSource = Resolvespecifieddatasource (Entry.getvalue ());        This.resolvedDataSources.put (LookupKey, DataSource); }//Ibid. parse default data source if (This.defaulttargetdatasource! = null) {This.resolveddefaultdatasource =Resolvespecifieddatasource (This.defaulttargetdatasource);    }    }? @Override public Connection getconnection () throws SQLException {///core, get data source first find the current connection pool and get the data source return Determi    Netargetdatasource (). getconnection ();    }? @Override Public Connection getconnection (string Username, string password) throws SQLException {return Determi    Netargetdatasource (). getconnection (username, password);    }? Protected DataSource Determinetargetdatasource () {//Call Determinecurrentlookupkey, then go to resolveddefaultdatasource find, there is        Returns the corresponding data source without returning 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.resolveddefa        Ultdatasource; } if (DataSource = = null) {throw new IllegalstAteexception ("Cannot determine target DataSource for lookup key [" + LookupKey + "]");    } return DataSource;    }//And Determinecurrentlookupkey need our own to achieve. It is often necessary to combine AOP and threadlocal. We AOP gets the data source that the current user wants from the annotation, and then sets it to the current thread. The Determinecurrentlookupkey is then taken out of the current thread and returned to Determinetargetdatasource to determine the final data source protected abstract Object Determinecurrentlookupkey ();?}

  

The above specific implementation can refer to this blog 77449710 It is important to note that the order of the AOP must precede the order of things.

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

Https://gitee.com/baomidou/dynamic-datasource-spring-boot-starter

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<string    , datasource> Datasourcemap;    /** * Packet Database */private map<string, dynamicgroupdatasource> groupdatasources = new hashmap<> ();    @Setter private Dynamicdatasourceprovider Dynamicdatasourceprovider; @Setter private class<?    Extends dynamicdatasourcestrategy> Dynamicdatasourcestrategyclass;    /** * Default data source name, default master, can be a group data source name, can be a single data source name */@Setter private String primary; @Override protected Object Determinecurrentlookupkey () {return Dynamicdatasourcecontextholder.getdatasourcelook    Upkey (); } @Override protected DataSource Determinetargetdatasource () {String lookupkey = (string) determinecurrentlo        Okupkey ();            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); } @Override public void Afterpropertiesset () {this.datasourcemap = Dynamicdatasourceprovider.loaddatasources        ();        Log.debug ("co-loading {} Data Sources", datasourcemap.size ()); Packet data source for (map.entry<string, datasource> dsItem:dataSourceMap.entrySet ()) {String DSName = ds            Item.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 Dynamicgro                        Updatasource (GroupName, Dynamicdatasourcestrategyclass.newinstance ());                        Groupdatasource.adddatasource (DataSource);                    Groupdatasources.put (GroupName, Groupdatasource);                    } catch (Exception e) {e.printstacktrace (); }}}}//detection group data source settings iterator<map.entry<string, dynamicgroupdatasource&        gt;> groupiterator = Groupdatasources.entryset (). iterator ();            while (Groupiterator.hasnext ()) {map.entry<string, dynamicgroupdatasource> 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        {}, there are {} data sources under it, 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.