Spring configuration multiple data source process

Here, AOP interception annotations are used to switch data sources.
1. Add new data source information in the data source configuration file context.xml, so that there are multiple database services that can be accessed. Pay attention to distinguish the jndi name.
2. Add the connection configuration of the new data source in the spring configuration file (usually spring.xml).
3. Create a new multi-data source class (such as MultipleDataSource.java), which needs to inherit from org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource
a) Add static properties to save data source information. Because threads do not need to access each other's data sources, ThreadLocal is used here to save the data source information of each thread

public class DataSourceContextLocal
{
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();

    public static void setDataSourceId(String dataSourceId)
    {
          //Add a static setting method to set the data source for the current thread
        contextHolder.set(dataSourceId);
    }

    public static String getDataSourceId()
    {
        return contextHolder.get();
    }

    public static void clearDataSourceId()
    {
        //Add a static cleanup method to use the default data source for unannotated methods
        contextHolder.remove();
    }
}

 

 

 

 b) Override the determineCurrentLookupKey() method. This method is used by spring jdbc to find data sources from targetDataSources. If it returns null, the default data source specified by defaultTargetDataSource is used (these properties are configured in step 4)

public class DynamicDataSource extends AbstractRoutingDataSource
{

    @Override
    protected Object determineCurrentLookupKey()
    {
        return DataSourceContextLocal.getDataSourceId();
    }

}

 4. Add beans of multiple data source classes in spring.xml

<!-- Multiple data sources -->
	<bean id="dynamicDataSource" class="com.iflytek.wh.base.dao.common.DynamicDataSource">
		<property name="targetDataSources">
			<map key-type="java.lang.String">
				<entry key="defaultDs" value-ref="defaultDs" />
			</map>
		</property>
		<property name="defaultTargetDataSource" ref="defaultDs" />
	</bean>

 a) Configure the attribute defaultTargetDataSource, and the ref value is one of several database connections. When no data source is specified, this connection is used by default.
b) The configuration attribute targetDataSources, the entry key of the map is freely defined to identify different data sources, and the value-ref points to the corresponding database connection.
6. Add a new annotation class, which needs to contain a string attribute. Due to the combination of AOP, it is necessary to specify that the reflection period is available, and the annotation acts on the method:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Used to switch data sources at the dao layer
 *
 * @author [email protected]
 *@date March 29, 2016 at 1:04:58 PM
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DataSource
{
    String name() default DataSource.defaultDs;

    public static String defaultDs = "defaultDs";

    public static String otherDs = "otherDs";

    public static String usercenterDs = "usercenterDs";

}

 

 7. Create a new AOP notification class. We need to switch the data source before the method is executed, so we need to implement the org.springframework.aop.MethodBeforeAdvice interface and rewrite the before(Method method, Object[] args, Object target) method:

 

import java.lang.reflect.Method;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;

import com.iflytek.wh.base.support.annotation.DataSource;

public class DataSourceSwitching implements MethodBeforeAdvice, AfterReturningAdvice {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        String fullMethodName = target.getClass().getSimpleName() + "." + method.getName();
        DataSource dataSource = method.getAnnotation(DataSource.class);
        if (dataSource != null) {
            String dataSourceName = dataSource.name();
            logger.debug(fullMethodName + ": switch to data source" + dataSourceName);
            DataSourceContextLocal.setDataSourceId(dataSourceName);
        } else {
            logger.debug(fullMethodName + ": use default data source");
            DataSourceContextLocal.clearDataSourceId();
        }
    }

    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target)
            throws Throwable {
        // DataSourceContextLocal.clearDataSourceId();
    }
}

 

 8. Since the interface implementation is configured with transaction management, the priority of the transaction will be higher than the data source switching. Once the transaction is opened, it is invalid to switch the data source, so it is necessary to modify their order here.
a) The notification class should implement the org.springframework.core.Ordered interface, and rewrite the getOrder() method to make it return 1;

<!-- Transaction-->
	<bean id="txManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
		p:dataSource-ref="dynamicDataSource" />
	<tx:annotation-driven transaction-manager="txManager"
		order="1" />

 In this way, Spring will execute the notification class method first, and then start the transaction.
9. Add the annotation @BiDSchoicer(dsName="dsname") to the interface method that needs to switch the data source (must be a method in the interface, invalid in the implementation method), and the attribute value must be the entry key of the configured targetDataSources attribute.
10. Create a new notification class bean in spring.xml, assuming the id is advice
11. Define the entry point, the expression attribute should be modified according to the situation, pointing to the implementation class

 

<!-- Annotation switch data source-->
	<aop:config>
		<aop:pointcut id="daoMapping"
			expression="execution(* com.iflytek..service.*.*(..))" />
		<!-- Key configuration, switching data source must be executed before persistence layer code (transaction is also considered persistence layer code) -->
		<aop:advisor advice-ref="dataSourceSwitching"
			pointcut-ref="daoMapping" order="0" />
	</aop:config>
	<bean id="dataSourceSwitching" class="com.iflytek.wh.base.dao.common.DataSourceSwitching" />

 After this configuration, you only need to add annotations to the interface method of the data source to modify it. After AOP intercepts the method, the data source will be set first. If there is an annotation, it will be set according to the annotation attribute. If there is no annotation, the default data source will be used. For those not intercepted by AOP, the default data source is used.

 

 

Reference address:

http://www.cnblogs.com/davidwang456/p/4318303.html

http://somefuture.iteye.com/blog/2306320

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326181678&siteId=291194637