Data Source Switching Based on different domain names

Source: Internet
Author: User

Recently, during project merging, projects (sub-projects) are separated from IDM projects (parent projects). Independent development is considered, but too many projects depend on IDM, so now we need to merge ....

The sub-project has an SaaS module, which is used to access different databases based on different domain names. It mainly uses the domain name interceptor and spring data source switching (abstractroutingdatasource ).

1: databases are divided into sub-databases and master databases. Sub-databases store business data and management sub-database information.

Mainly two tables

Database connection information

The correspondence between the domain name and the database connection information. Here, dbconnid corresponds to the ID of the rising table.

In this way, messages from multiple databases are stored in the master database.

2 domain name interceptor

The common interceptor intercepts domain names of level 2 for all requests and saves them to a basic class threadlocalutil.

For example: http://xl.test.com/test here to obtain the XL Level 2 domain name, save to the basic class threadlocalutil, convenient to connect to the database according to this domain name.

 

@ Override
Public void dofilter (servletrequest request, servletresponse response, filterchain chain) throws ioexception, servletexception {
Try {
String servername = request. getservername ();
String sec = "";
If (iputil. isip (servername) {// here, if the IP address is the default master database
SEC = iconstant. WWW;
} Else {
SEC = domainutil. getsecond (servername );
}
List <string> alldomain = domainutil. getalldomain ();
If (alldomain. Contains (SEC )){
Threadlocalutil. setsecdomain (SEC );
If (threadlocalutil. isdefsecdomain ()){
Log. debug ("default domain name {}, url = {}", SEC, servername );
}
Chain. dofilter (request, response );
} Else {
Httpservletrequest Req = (httpservletrequest) request;
Httpservletresponse resp = (httpservletresponse) response;
String requri = Req. getrequesturi ();
For (string exclude: Excludes ){
If (requri. Contains (exclude )){
Chain. dofilter (request, response );
Return;
}
}
Resp. setstatus (httpservletresponse. SC _not_found );
Resp. sendredirect (req. getcontextpath () + "/error/404.jsp ");
}
} Finally {
Threadlocalutil. delsecdomain ();
}
}

3. Initialization Method

Here is an initialization method, which obtains all the SAAs data of the database and adds it to multidatasource. The map, key domain name, and value database information passed in here is adddatasource.

4: The Key multidatasource. This class inherits the abstractroutingdatasource.

The abstractroutingdatasource class is also the key to data source switching.

 

 

 

 

This class is connected to the data source based on this method, and the key is the lookupkey object, that is, the determinecurrentlookupkey method. This method of this class is abstract, and the specific implementation is determined by the subclass; next, we will refer

The map of resolveddatasources is obtained here. Of course, the map method of set is provided here, but it is not direct or indirect.

Source:

 

Map variables in the class

Private Map <object, Object> targetdatasources;

Private Map <object, datasource> resolveddatasources;

 

How to connect to a data source

Protected datasource determinetargetdatasource (){
Assert. notnull (this. resolveddatasources, "datasource router not initialized ");
Object lookupkey = determinecurrentlookupkey ();
Datasource = This. resolveddatasources. Get (lookupkey );
If (datasource = NULL & (this. lenientfallback | lookupkey = NULL )){
Datasource = This. resolveddefadatasource datasource;
}
If (datasource = NULL ){
Throw new illegalstateexception ("cannot determine target datasource for lookup key [" + lookupkey + "]");
}
Return datasource;
}

 

Abstract Method

Protected abstract object determinecurrentlookupkey ();

 

The Set resolveddatasources method uses the targetdatasources map. Here is the method to set targetdatasources directly.

@ Override
Public void afterpropertiesset (){
If (this.tar getdatasources = NULL ){
Throw new illegalargumentexception ("Property 'targetdatasources 'is required ");
}
This. resolveddatasources = new hashmap <object, datasource> (this.tar getdatasources. Size ());
For (Map. Entry <object, Object> entry: this.tar getdatasources. entryset ()){
Object lookupkey = resolvespecifiedlookupkey (entry. getkey ());
Datasource = resolvespecifieddatasource (entry. getvalue ());
This. resolveddatasources. Put (lookupkey, datasource );
}
If (this. defaulttargetdatasource! = NULL ){
This. resolveddefadatasource datasource = resolvespecifieddatasource (this. defaulttargetdatasource );
}
}

 

Set targetdatasources Method

Public void settargetdatasources (Map <object, Object> targetdatasources ){
This.tar getdatasources = targetdatasources;
}

 

Here we implement this.

Here, the domain name stored by the domain name interceptor is used to determine which database to connect.

@ Override
Protected object determinecurrentlookupkey (){
String secdomain = threadlocalutil. getsecdomain (); Save it here.
If (! Iconstant. www. Equals (secdomain )){
Return secdomain;
} Else {
Log. debug ("default domain name {}", secdomain );
}
Return def;
}

We must have called its set method here.

Public void settargetdatasources (Map <object, Object> targetdatasources ){
This.tar getdatasources = targetdatasources;
Super. settargetdatasources (targetdatasources); call the Set Method of the parent class.
Tdsversion ++;
}

Method called during initialization


/**
* Multiple database connection pools are added.
*
* @ Param Conns
*/
Public void adddatasource (Map <string, dbconninfo> Conns ){
If (null! = Conns & Conns. Size ()> 0 ){
Linkedhashmap <object, Object> newtargetdatasources = new linkedhashmap <> (targetdatasources );
Set <string> keys = Conns. keyset ();
For (string key: Keys ){
Dbconninfo conn = Conns. Get (key );
Datasource DS = builddatasource (conn );
Newtargetdatasources. Put (Key, DS );
Domaindbconnmap. Put (Key, Conn );
}
Settargetdatasources (newtargetdatasources); // here, the key is the map of the domain name value as the database connection information, set to targetdatasources.
Afterpropertiesset (); // This method needs to be called after the connection information is changed.
}
}

 

In this way, the database is switched based on the domain name.

0 system initialization --- 1 user request -- 2 domain name interceptor -- 3 Switch data source.

The write is a bit messy ..

For details about how to switch the data source, refer to this address carefully.

53965552

 

Data Source Switching Based on different domain names

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.