As business changes/requirements change, Java EE applications are forced to connect multiple data sources for business processing.
How do you dynamically switch data sources in the most elegant/concise way without affecting the original project structure?
This article has once added the data source after the dynamic switch practice as an example, describes the whole thought and the practice process, the article if has the mistake, also looks correct.
1. Rely on Spring Dynamic Data source implementation
Spring provides an abstract routed data source object called Abstractroutingdatasource inherited from Abstractdatasource and implements the DataSource interface in the JDK.
It also means that the class that inherits Abstractroutingdatasource and rewrites it determinecurrentlookupkey methods can act as a data source and personalize multiple data source dynamic routing switching.
(If you are usually careful enough, the current open source database connection pool is implemented DataSource interface and has its own personalized encapsulation.) )
Public class extends Abstractroutingdatasource { @Override protected Object Determinecurrentlookupkey () { return dbcontextholder.getdbtype (); }}
For a Web request to be understood as a separate thread, it is reasonable to hold the current data source in the threads.
Public classDbcontextholder {Private Static FinalThreadLocal Contextholder =NewThreadlocal<>(); /*** Set Data source * *@paramDbsourceenum The name of the database enumeration to set*/ Public Static voidSetdbtype (Dbsourceenum dbsourceenum) {Contextholder.set (Dbsourceenum.getvalue ()); } /*** Get Current data source*/ Public StaticString Getdbtype () {returnstring.valueof (Contextholder.get ()); } /*** Clear Contextual data*/ Public Static voidCleardbtype () {contextholder.remove (); }}
Of course, for later expansion and maintenance, and the ease of use, here the data source object We introduce the enumeration type.
This allows other colleagues to programmatically use enumerations, which can be quite convenient to change, as well as some custom markers for two of data sources.
Public enum Dbsourceenum {One ("DataSource1"), and one ("DataSource2") ; Private String value; Dbsourceenum (String value) { this. Value = value; } Public String GetValue () { return value; }}
The above datasource1/datasource2 is the Id of the data source object that was loaded in Spring-context.
< Bean name = "DataSource1" class = "Com.alibaba.druid.pool.DruidDataSource" Init-method = "Init" Destroy-method = "Close" > ...... </ bean >
<name= "DataSource2" class= " Com.alibaba.druid.pool.DruidDataSource " init-method=" Init " destroy-method = "Close"> ... </ Bean >
Next, configure the Dynamicdatasource that inherits from Abstractroutingdatasource in the context.
<BeanID= "DataSource"class= "Com.rambo.spm.core.multidb.DynamicDataSource"> < Propertyname= "Targetdatasources"> <MapKey-type= "Java.lang.String"> <entryKey= "DataSource1"Value-ref= "DataSource1"/> <entryKey= "DataSource2"Value-ref= "DataSource2"/> </Map> </ Property> < Propertyname= "Defaulttargetdatasource"ref= "DataSource1"/> </Bean>
Ok to use this dynamicdatasource when configuring the subsequent DAO layer.
2. The most elegant way to switch data sources
After doing this, the dynamic switching of the data source object is already working, and is programmed in the business layer as follows.
Dbcontextholder.setdbtype (dbsourceenum.one); List<Menu> menulist = menuservice.selectlist (null); Dbcontextholder.setdbtype (dbsourceenum.two); List<User> userlist = userservice.selectlist (null);
The disadvantage is obvious, connected to the data source 2 o'clock to switch/not conducive to the expansion/switchover is not at that time to bury the thunder of the chances of a great.
When communicating with the team, we discuss a scheme that uses powerful AOP to intercept DAO layer objects and dynamically switch data sources.
For DAO layer objects, which table to access the database is deterministic, write custom annotations, and bind to the DAO layer object.
The custom data source annotations are as follows:
@Inherited @retention (retentionpolicy.runtime) @Target (elementtype.type) public @Interface DataSource { default dbsourceenum.one;}
write the slice processing object, intercept the DAO layer object before use, switch the data source conveniently, if there is no data source annotation, set as default.
So for the first data source in the original project DAO layer object, there is no need to make any modifications, the slice processing is as follows.
@Before ("Cut ()") publicvoid dobefore (joinpoint joinpoint) { = Joinpoint.gettarget (). GetClass (). Getannotation (DataSource. Class); null ? datasource.value (): Dbsourceenum.one); Log.info ("Current data source is:" + Dbcontextholder.getdbtype ()); }
The intricate abstraction and inheritance of the DAO layer in most projects will make it difficult for you to intercept AOP slices, and there is always a way to think and practice more.
Well, that's it, isn't it? It's easier to extend, program, understand, and, of course, be more elegant than an AOP interception method, which is more extensible, more programmable, more understandable, and more difficult to code.
Code already hosted in: Https://git.oschina.net/LanboEx/spmvc-mybatis.git interested friends, you can check the local run.
What is the most graceful way to switch Web project data sources?