Spring AOP Dynamically sets the data source based on the JdbcTemplate method name

Source: Internet
Author: User
Tags aop

Description: The current scenario is to deploy and configure Master-slave (Master-slave) relationships in two different servers in a database (MYSQL) replication (binlog) manner;
and requires a program of data manipulation methods to access different databases, such as the update method to access the primary database server, the query method access from the database server.
That is, "adding and deleting" and "check" separate access to two servers, of course, the database synchronization of two servers has been configured beforehand.
However, the program is already completed using the Spring JdbcTemplate architecture, how to do not modify any source code in the case of < this article title > function?
Analysis:
1. There are currently two data sources that need to be configured in the Spring framework, how do you manage the two data sources in a unified way?
JdbcTemplate has many database operation methods, the key can be divided into the following categories (using concise wildcard characters): Execute (args.), update (args.), BatchUpdate (args.), query* (args.)

Args: Represents a parameter that can be any argument or no parameter.

2. How can I use different data sources based on these method names?
3. Transaction management for multiple data sources (not the focus of this article).
Realize:
Spring configuration file Applicationcontext.xml (contains code for the related bean Class)
1. Data source configuration (more detailed connection parameter settings omitted):
Class= "Org.apache.commons.dbcp.BasicDataSource"
destroy-method= "Close" >
Value= "${jdbc.driverclassname}"/>
06
07
08
09
10
11
Class= "Org.apache.commons.dbcp.BasicDataSource"
destroy-method= "Close" >
Value= "${jdbc.driverclassname}"/>
17
18
19
20
21st
22
class= "Test.my.serivce.ds.DynamicDataSource" >
25
26
27
28
29
30
31
32
First, the definition of two data sources (connection address and user name and other data stored in the Properties property file), spring can set up a number of data sources, it is simply a normal bean.
The key is the set of the bean with the id "DataSource", which is an example of this class "Test.my.serivce.ds.DynamicDataSource":
1 Import Org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
2
3 public class Dynamicdatasource extends Abstractroutingdatasource {
4 @Override
5 protected Object Determinecurrentlookupkey () {
6 return Customercontextholder.getcustomertype ();
7}
8}

The Dynamicdatasource class inherits the abstract class Abstractroutingdatasource of spring, The Abstractroutingdatasource itself implements the Javax.sql.DataSource interface (implemented by its parent abstract class Abstractdatasource), so it is actually an implementation class for a standard data source. This class is an interface layer added by spring specifically for multi-data source management, see Spring-api-doc:
Abstract DataSource Implementation, Routes getconnection () calls to one of the various target datasources based on a Looku P Key. The latter is usually (and not necessarily) determined through some thread-bound transaction context.
It uniquely identifies a key based on a data source to find a configured data source queue, which is usually bound to the current thread.
View its source code, know that it also implements the spring initialization method class Initializingbean, this class has only one method: Afterpropertiesset (), Called by spring after the initialization of the bean is completed (according to the method name Association should be set to all properties before calling, the actual same is true):
Afterpropertiesset public void () {
if (this.targetdatasources = = null) {
IllegalArgumentException throw New ("Targetdatasources is required");
04}
This.resolveddatasources = new HashMap (This.targetDataSources.size ());
for (Iterator it = This.targetDataSources.entrySet (). Iterator (); It.hasnext ();) {
Map.entry Entry = (map.entry) it.next ();
Object LookupKey = Resolvespecifiedlookupkey (Entry.getkey ());
DataSource DataSource = Resolvespecifieddatasource (Entry.getvalue ());
Ten This.resolvedDataSources.put (LookupKey, DataSource);
11}
if (This.defaulttargetdatasource! = null)
This.resolveddefaultdatasource = Resolvespecifieddatasource (This.defaulttargetdatasource);
14}
To view its implementation, spring stores all configured data sources in a HashMap object named Targetdatasources (the Targetdatasources property must be set, otherwise the exception The Defaulttargetdatasource property can not be set). Just keeping the data source in one map is not what you can do, and the key is that it also overrides the Javax.sql.DataSource getconnection () method, which is used whenever you use database operation-related methods, even if ibatis, The bottom layer of a multi-layered package, such as Hibernate, JPA, is also implemented using the most common JDBC.
Connection getconnection () throws SQLException {
Determinetargetdatasource return (). getconnection ();
03}
Protected DataSource Determinetargetdatasource () {
Object LookupKey = Determinecurrentlookupkey ();
DataSource DataSource = (DataSource) this.resolvedDataSources.get (LookupKey);
if (DataSource = = null)
DataSource = This.resolveddefaultdatasource;
DataSource if (= = null)
Ten throw new IllegalStateException ("cannot determine target DataSource for lookup key [" + LookupKey + "]");
return dataSource;
12}
Protected object Resolvespecifiedlookupkey (object LookupKey) {
LookupKey return;
15}
Protected abstract Object Determinecurrentlookupkey ();
Omitting part of the checksum code, here is a key method that must be used: Determinecurrentlookupkey, which is also an abstraction with your own implementation method, returns the key from the data source that you actually want to use (that is, the ID of the data source bean that you configured earlier). Detailed instructions can be found from the Spring-api-doc:
Determine the current lookup key. This would typically is implemented to check a Thread-bound transaction context. allows for arbitrary keys. The returned key needs to match the stored lookup key type.
It allows any type of key, but must be consistent with the key type saved to the data source HashMap. We can specify this type in the spring configuration file, and it is a good idea to have a very restrictive view on the web to see someone using enum types.
Our "Test.my.serivce.ds.DynamicDataSource" implements this method, which shows that the specific data source key is obtained from the Customercontextholder class and is also bound to the current thread using key:
public class Customercontextholder {
The private static final ThreadLocal Contextholder = new ThreadLocal ();
public static void Setcustomertype (String customertype) {
Contextholder.set (CustomerType);
05}
public static String Getcustomertype () {
"Return (String) contextholder.get ();
08}
Clearcustomertype public static void () {
Ten Contextholder.remove ();
11}
12}
We can also use global variables to store this key. I didn't know java.lang.ThreadLocal before, then charge the electricity: http://java.dzone.com/articles/java-thread-local-–-how-use
Even one reviewer, sharply, pointed out the question:
Why are userthreadlocal declared public? AFAIK, ThreadLocal instances is typically private static fields. Also, ThreadLocal is a generic type, it is ThreadLocal. An important benefit of ThreadLocal worth mentioning (from 1.4 JVMs forward), is as a alternative to synchronization, to Improve scalability in transaction-intensive environments. Classes encapsulated in ThreadLocal is automatically thread-safe in a pretty simple, since it's clear that anything s Tored in ThreadLocal are not shared between threads.
Threadlocal are thread-safe and cannot be shared across multiple threads. Based on this principle, I have written the following small examples to further understand:
public class Test {
The private static ThreadLocal TL = new ThreadLocal ();
Geneva public static void main (string[] args) {
Tl.set ("abc");
System.out.println (Tl.get ());
The new Thread (new Runnable () {
public void Run () {
System.out.println (Tl.get ());
09}
). Start ();
11}
12}
To do this, we have solved the first problem, but it does not seem to get to the point, how to dynamically set the data source according to the JdbcTemplate method name?
2.Spring AOP Cut-in JdbcTemplate method configuration:
01
02
03
expression= "Execution (org.springframework.jdbc.core.JdbcTemplate.update(..)) || Execution (Org.springframework.jdbc.core.JdbcTemplate.batchUpdate (..)) " />
pointcut-ref= "Update"/>
,

09
Ten pointcut= "Execution (
Org.springframework.jdbc.core.JdbcTemplate.query(..)) || Execution (Org.springframework.jdbc.core.JdbcTemplate.execute (..)) " />
12
13
You can see that I have used the 4 class methods of JdbcTemplate to intercept and use a pre-notification method () to invoke other methods before executing these methods, and I will not elaborate on the meaning of the specific AOP expression language.
What exactly is this method, based on the first instructions, intercepting the update operation and the select operation separately and invoking different methods?
is to give Threadlocal the name of the data source (key) so that Dynamicdatasource knows exactly which data source to use.

The predecessor method is to invoke a set method of the "Test.my.serivce.ds.BeforeAdvice" class:
1 public class Beforeadvice {
2 public void Setmasterdatasource () {
3 Customercontextholder.setcustomertype ("Master");
4}
5 public void Setslavedatasource () {
6 Customercontextholder.setcustomertype ("Slave");
7}
8}
The current thread will save the key name that is set in and can be called at any time.
Finally, you can configure a jdbctemplate bean.
1 2 class= "Org.springframework.jdbc.core.JdbcTemplate" >
3
4
Note:
1. A problem encountered during the resolution process:
Spring exception: No matching editors or conversion strategy found
Reference: http://blog.csdn.net/zzycgfans/article/details/6316081
Reference: Spring injects an interface, which is associated with an implementation class. The implementation class is injected here, so the report is abnormal.
2. The main articles of this article are:
This article also contains the configuration for transaction management: http://hi.baidu.com/litianyi520/blog/item/71279e3e180db6f1838b1327.html
The setting of this article and the multi-data source is instructive to me (also includes the test case): http://oiote.blog.sohu.com/74596942.html
Previously done ibatis using Ehcache and Oscache cache configuration, this article is somewhat similar: http://lihaiyan.iteye.com/blog/127818
Some real-world scenario analysis of multi-data sources, the theory is heavier than the actual: http://hi.baidu.com/freeway2000/blog/item/ba0906f4946fa8eb7709d716.html
In addition, some articles of Javaeye (now Iteye) are of reference value: http://www.iteye.com/wiki/blog/1229655
EOF. The original idea came to a reality here. This article describes the entire implementation process and some superficial analysis of "Spring AOP dynamically sets the data source based on the JdbcTemplate method name."
After using this configuration, the problem is still found in the actual use. For example, call the Query method to query the record immediately after calling JdbcTemplate's Update method, or use the following method:
This.jdbcTemplate.update (New PreparedStatementCreator (), Keyholder)
Because the database replication has a synchronization gap, which is later than the program's call, there is a situation where the data is not queried, in fact, the data is not synchronized to the slave server. Looking for a better solution!

Spring AOP Dynamically sets the data source based on the JdbcTemplate method name

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.