AbstractRoutingDataSource and SpringSecurity making dynamic swappable datasources based on Principal

The situation occurs where multiple databases that mirror one another needs to be interchanged dynamically at runtime. If a user needs to dynamically switch between them, spring has a very nice solution called AbstractRoutingDataSource. This can be used as a proxy where the user can simply swap datasources. However, the scope of the swap impacts the application globally. There are instances where the swap should only occur for the single principal requesting the change. This can be very useful in several situations. There is a solution described here http://blog.springsource.com/2007/01/23/dynamic-datasource-routing/ that will allow a variable defined in the users context to determine which datasource is utilized. This solution uses the ThreadLocal class.

Below is another simplistic solution that enables SpringSecurity to statically store the database name based on the unique principal. This avoids having to use the ThreadLocal which could potentially cause problems.

public class PrincipalRoutingDataSource extends AbstractRoutingDataSource {
	private static Map<Object, String> databaseMap = new HashMap<Object, String>();
	private String targetDataSource = null;
	private String defaultTargetDataSourceKey;
	public String getDataSourceName() {
		return (String)determineCurrentLookupKey();
	public void setDefaultTargetDataSourceKey(String defaultTargetDataSourceKey) {
		this.defaultTargetDataSourceKey = defaultTargetDataSourceKey;
	public void setTargetDataSource(String key) {
		Object o = getPrincipal();
		if (o != null) {
			databaseMap.put(getPrincipal(), key); //principal is the key, 'key' is the database name
	protected Object determineCurrentLookupKey() {
		if (getPrincipal() != null) {
			String database = databaseMap.get(getPrincipal());
			if (database!= null)
				return database;
		if (targetDataSource == null)
			targetDataSource = defaultTargetDataSourceKey;
		return targetDataSource;
	protected Object getPrincipal() {
		SecurityContext sc = SecurityContextHolder.getContext();
		if (sc != null) {
			Authentication auth = sc.getAuthentication();
			if (auth != null)
				return auth.getPrincipal();
		return null;

And the bean definition is as follows.

<bean id="dataSourceProvider" class="com.test.datasource.lookup.PrincipalRoutingDataSource">
	<property name="targetDataSources">
            <map key-type="java.lang.String" value-type="javax.sql.DataSource">
		<entry key="${db1}" value-ref="dataSource1"/>
		<entry key="${db2}" value-ref="dataSource2"/>
		<entry key="${db3}" value-ref="dataSource3"/>
        <property name="defaultTargetDataSource" ref="dataSource1"/>
        <property name="defaultTargetDataSourceKey" value="${db1}"/>

Now dynamically in the code you can swap them based on the database name. This will only swap for the unique principal.

	private PrincipalRoutingDataSource routingDataSource;
	public String getDataSourceName() {
		return this.routingDataSource.getDataSourceName();
	public void setDataSourceName(String dataSourceName) {
		System.out.println("Rerouting Datasource : " + getDataSourceName() + " to " + dataSourceName);
		System.out.println("Datasource rerouted : " + getDataSourceName());

Post new comment

Subscribe to Syndicate