This article is based on spring 4.1.6 release source code analysis.
Let's take a look at the Dynamic Data sources we configured in the Spring-mybatis.xml file, as follows:
<bean id= "DataSource" class= "Com.ricky.codelab.spring.ds.DynamicRoutingDataSource" >
<property name= " Targetdatasources ">
<map key-type=" Com.ricky.codelab.spring.ds.RouteStrategy ">
<entry key=" Slave1 "value-ref=" Slave1datasource "/>
<entry key=" slave2 "value-ref=" Slave2datasource "/>
</ map>
</property>
<!--default Target data source primary library data source-
<property name= "Defaulttargetdatasource" ref = "Masterdatasource"/>
</bean>
Dynamicroutingdatasource inherits from the Abstractroutingdatasource class with the following code:
Package com.ricky.codelab.spring.ds;
Import Org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* Dynamic Data source Toggle
*
* @author Ricky Fung
* @create 2016-10-18 22:41
*/public class Dynamicroutingdatasource extends Abstractroutingdatasource {
@Override
protected Object Determinecurrentlookupkey () {
return dynamicroutingcontextholder.getroutestrategy ();
}
}
The definition of Abstractroutingdatasource class, the source code is as follows:
Package org.springframework.jdbc.datasource.lookup;
Public abstract class Abstractroutingdatasource extends Abstractdatasource implements Initializingbean {
private Map<object, object> targetdatasources;
Private Object Defaulttargetdatasource;
Private Boolean lenientfallback = true;
Private Datasourcelookup datasourcelookup = new Jndidatasourcelookup ();
Private Map<object, datasource> resolveddatasources;
Private DataSource resolveddefaultdatasource;
}
Abstractroutingdatasource implements the Initializingbean interface, and the spring container starts with a callback to its Afterpropertiesset () method, Abstractroutingdatasource Afterpropertiesset () is as follows:
public void Afterpropertiesset () {if (this.targetdatasources = = null) {throw new IllegalArgumentException ("Pr
Operty \ ' targetdatasources\ ' is required ");
} else {this.resolveddatasources = new HashMap (This.targetDataSources.size ());
Iterator var1 = This.targetDataSources.entrySet (). Iterator ();
while (Var1.hasnext ()) {Entry Entry = (Entry) var1.next ();
Object LookupKey = This.resolvespecifiedlookupkey (Entry.getkey ());
DataSource DataSource = This.resolvespecifieddatasource (Entry.getvalue ());
This.resolvedDataSources.put (LookupKey, DataSource); } if (This.defaulttargetdatasource! = null) {This.resolveddefaultdatasource = This.resolvespecifiedda
Tasource (This.defaulttargetdatasource); }}} protected DataSource Resolvespecifieddatasource (Object DataSource) throws IllegalArgumentException {if (da Tasource instanceof DataSource) {return (DataSource) dAtasource;
} else if (DataSource instanceof String) {return This.dataSourceLookup.getDataSource ((String) dataSource); } else {throw new illegalargumentexception ("illegal data source value-only [Javax.sql.DataSource] and String su
pported: "+ dataSource); }
}
This mainly resolves the targetdatasources configured in XML to the Resolveddatasources,defaulttargetdatasource assignment to Resolveddefaultdatasource.
In addition, Abstractroutingdatasource inherits from Abstractdatasource, and Abstractdatasource is a subclass of DataSource, as follows:
Package Org.springframework.jdbc.datasource;
Public abstract class Abstractdatasource implements DataSource {
protected final Log logger = Logfactory.getlog (this. GetClass ());
Public Abstractdatasource () {
}
}
Therefore, we only need to see Abstractroutingdatasource's getconnection () method implementation, as follows:
Public Connection getconnection () throws SQLException {
return This.determinetargetdatasource (). getconnection ();
} public
Connection getconnection (string Username, string password) throws SQLException {
return This.determinetargetdatasource (). getconnection (username, password);
}
The Determinetargetdatasource () method is as follows:
Protected DataSource Determinetargetdatasource () {
assert.notnull (this.resolveddatasources, "DataSource router Not initialized ");
Object LookupKey = This.determinecurrentlookupkey ();
DataSource DataSource = (DataSource) this.resolvedDataSources.get (lookupkey);
if (DataSource = = null && (This.lenientfallback | | lookupkey = = NULL)) {
DataSource = This.resolveddefaultdata Source;
}
if (DataSource = = null) {
throw new IllegalStateException ("cannot determine target DataSource for lookup key [" + Looku PKey + "]");
} else {
return dataSource;
}
}
The Determinetargetdatasource method determines which DataSource object is returned, It gets the key of the data source according to the Determinecurrentlookupkey method, which is the method that we override in the Dynamicroutingdatasource class, and then from the Resolveddatasources The DataSource is taken from key, if the returned datasource is empty, the default datasource is used.