Spring AOP dynamic multi-data source instance details, Spring AOP
Examples of Spring AOP dynamic multi-data sources
When read/write splitting is used in the project, we will encounter multiple data sources. Multiple data sources are the biggest headache. Instead of configuring multiple data sources, you can flexibly and dynamically switch data sources. For example, in a spring and Mybatis framework project, we usually configure a dataSource in spring configuration to connect to the database and then bind it to sessionFactory, in the dao-Layer Code, specify sessionFactory to perform database operations.
As shown in, each part is bound to a dead part. If multiple data sources exist, it can only be in the middle way.
It can be seen that two sessionfactories are written in the Dao-Layer Code. In this way, if there is another data source in the future, you need to change the code to add a SessionFactory. Obviously, this is not in line with the open/closed principle.
The correct method should be:
The code and configuration are as follows:
1. applicationContext-mgr.xml
<? Xml version = "1.0" encoding = "UTF-8"?> <Beans xmlns =" http://www.springframework.org/schema/beans "Xmlns: xsi =" http://www.w3.org/2001/XMLSchema-instance "Xmlns: aop =" http://www.springframework.org/schema/aop "Xmlns: context =" http://www.springframework.org/schema/context "Xmlns: tx =" http://www.springframework.org/schema/tx "Xmlns: p =" http://www.springframework.org/schema/p "Xsi: schemaLocation =" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans Spring-beans-2.5.xsd http://www.springframework.org/schema/aop Spring-aop-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context Spring-context-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx /Spring-tx-2.5.xsd "> <! -- Use annotation --> <context: annotation-config/> <context: component-scan base-package = "com. carl. o2o. **. mgr "> </context: component-scan> <! -- Master --> <bean id = "master" class = "com. mchange. v2.c3p0. comboPooledDataSource "> <property name =" driverClass "value =" $ {driverClassName_master} "/> <property name =" user "value =" $ {username_master} "/> <property name = "password" value = "$ {password_master}"/> <property name = "jdbcUrl" value = "$ {url_master }? Unicode = true & characterEncoding = UTF-8 & allowMultiQueries = true "/> <property name =" maxPoolSize "value =" 150 "/> <property name =" minPoolSize "value =" 10" /> <property name = "initialPoolSize" value = "20"/> <property name = "maxIdleTime" value = "3600"/> <property name = "acquireIncrement" value =" 10 "/> <property name =" idleConnectionTestPeriod "value =" 1800 "/> </bean> <! -- Slave --> <bean id = "slave" class = "com. mchange. v2.c3p0. comboPooledDataSource "> <property name =" driverClass "value =" $ {driverClassName_slave} "/> <property name =" user "value =" $ {username_slave} "/> <property name = "password" value = "$ {password_slave}"/> <property name = "jdbcUrl" value = "$ {url_slave }? Unicode = true & characterEncoding = UTF-8 "/> <property name =" maxPoolSize "value =" 150 "/> <property name =" minPoolSize "value =" 10 "/> <property name = "initialPoolSize" value = "20"/> <property name = "maxIdleTime" value = "3600"/> <property name = "acquireIncrement" value = "10"/> <property name = "idleConnectionTestPeriod" value = "1800" type = "codeph" text = "codeph"/> </bean> <! -- Spring dynamic data source --> <bean id = "dynamicDataSource" class = "com. carl. dbUtil. dynamicDataSource "> <property name =" targetDataSources "> <map key-type =" java. lang. string "> <entry key =" slave "value-ref =" slave "/> </map> </property> <property name =" defaultTargetDataSource "ref =" master "/> </bean> <! -- Mybatis mapper config --> <bean id = "sqlSessionFactory" class = "org. mybatis. spring. sqlSessionFactoryBean "> <property name =" dataSource "ref =" dynamicDataSource "/> <property name =" configLocation "value =" classpath: o2o_mybatis_config.xml "/> <property name =" mapperLocations "> <list> <value> classpath: sqlMap /*. xml </value> <value> classpath *:/com/carl/o2o /**/*. xml </value> </list> </property> </bean> <bean I D = "sqlSession" class = "org. mybatis. spring. sqlSessionTemplate "> <constructor-arg index =" 0 "ref =" sqlSessionFactory "> </constructor-arg> </bean> <bean class =" org. mybatis. spring. mapper. mapperScannerConfigurer "> <property name =" basePackage "value =" com. carl. o2o. **. mgr. dao "/> </bean> <! -- Multi-data source aop --> <bean id = "ceceaspect" class = "com. carl. dbUtil. performanceaspect "/> <aop: config> <aop: advisor pointcut =" execution (* com. carl. o2o. mgr. *. *(..)) "advice-ref =" DataSourceAspect "/> </aop: config> <! -- Transaction --> <bean name = "transactionManager" class = "org. springframework. jdbc. datasource. dataSourceTransactionManager "> <property name =" dataSource "ref =" dynamicDataSource "> </property> </bean> </beans>
2. DynamicDataSource
DynamicDataSource uses the code in Spring and AOP to implement multi-data source switching.
public class DynamicDataSource extends AbstractRoutingDataSource { public DynamicDataSource() { } protected Object determineCurrentLookupKey() { return DBContextHolder.getDbType(); } public Logger getParentLogger() { return null; }}
3. DBContextHolder
The auxiliary class of DynamicDataSource for switching multiple data sources.
public class DBContextHolder { private static ThreadLocal<String> contextHolder = new ThreadLocal(); public static String MASTER = "master"; public static String SLAVE = "slave"; public DBContextHolder() { } public static String getDbType() { String db = (String)contextHolder.get(); if(db == null) { db = MASTER; } return db; } public static void setDbType(String str) { contextHolder.set(str); } public static void setMaster() { contextHolder.set(MASTER); } public static void setSlave() { contextHolder.set(SLAVE); } public static void clearDBType() { contextHolder.remove(); }}
4. performanceaspect
Multi-Data Source AOP aspect programming implementation.
public class DataSourceAspect implements MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice { private static final Logger log = LogManager.getLogger(DataSourceAspect.class); public DataSourceAspect() { } public void before(Method m, Object[] args, Object target) throws Throwable { try { if(m != null) { if((m.getName().startsWith("list") || m.getName().startsWith("select") || m.getName().startsWith("get") || m.getName().startsWith("count")) && !m.getName().contains("FromMaster")) { DBContextHolder.setDbType("slave"); } else { DBContextHolder.setDbType("master"); } } } catch (Exception var5) { log.error("data source aspect error.", var5); } } public void after(JoinPoint point) { log.info("clear db type after method.current id {}", new Object[]{Long.valueOf(Thread.currentThread().getId())}); DBContextHolder.clearDBType(); } public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { } public void afterThrowing(Method method, Object[] args, Object target, Exception ex) throws Throwable { log.info("current db type {} when exception", new Object[]{DBContextHolder.getDbType()}); DBContextHolder.setDbType("master"); }}
The above is an example of Spring AOP dynamic multi-data source. If you have any questions, please leave a message or go to the community on this site for discussion. Thank you for reading this article and hope to help you. Thank you for your support for this site!