Spring-基于Spring使用自定義注解及Aspect實(shí)現(xiàn)數(shù)據(jù)庫(kù)切換操作
實(shí)現(xiàn)思路
重寫Spring的AbstractRoutingDataSource抽象類的determineCurrentLookupKey方法。
我們來(lái)看下Spring-AbstractRoutingDataSource的源碼

AbstractRoutingDataSource獲取數(shù)據(jù)源之前會(huì)先調(diào)用determineCurrentLookupKey方法查找當(dāng)前的lookupKey。
Object lookupKey = determineCurrentLookupKey(); DataSource dataSource = this.resolvedDataSources.get(lookupKey); ....... return dataSource;
lookupKey為數(shù)據(jù)源標(biāo)識(shí),因此通過(guò)重寫這個(gè)查找數(shù)據(jù)源標(biāo)識(shí)的方法就可以讓spring切換到指定的數(shù)據(jù)源.
從變量定義中可以知道resolvedDataSources為Map類型的對(duì)象。
private Map<Object, DataSource> resolvedDataSources;
示例

步驟一 新建Maven工程
依賴如下: pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.artisan</groupId>
<artifactId>dynamicDataSource</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>dynamicDataSource</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<file.encoding>UTF-8</file.encoding>
<spring.version>4.3.9.RELEASE</spring.version>
<servlet.version>3.1.0</servlet.version>
<aspectj.version>1.8.1</aspectj.version>
<commons-dbcp.version>1.4</commons-dbcp.version>
<jetty.version>8.1.8.v20121106</jetty.version>
<log4j.version>1.2.17</log4j.version>
<log4j2.version>2.8.2</log4j2.version>
<testng.version>6.8.7</testng.version>
<oracle.version>11.2.0.4.0</oracle.version>
<jstl.version>1.2</jstl.version>
</properties>
<dependencies>
<!-- spring 依賴 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>${commons-dbcp.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${testng.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<!-- oracle jdbc driver -->
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>${oracle.version}</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${testng.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<!--
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j2.version}</version>
</dependency>
</dependencies>
<build>
<!-- 使用JDK1.7編譯 -->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
步驟二 繼承AbstractRoutingDataSource并重寫determineCurrentLookupKey方法獲取特定數(shù)據(jù)源
package com.artisan.dynamicDB;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
*
*
* @ClassName: DynamicDataSource
*
* @Description:
* AbstractRoutingDataSource中的抽象方法determineCurrentLookupKey是實(shí)現(xiàn)數(shù)據(jù)源的route的核心
* .需要重寫該方法
*
* @author: Mr.Yang
*
* @date: 2017年7月24日 下午8:28:46
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceHolder.getDataSource();
}
}
步驟三 創(chuàng)建DynamicDataSourceHolder用于持有當(dāng)前線程中使用的數(shù)據(jù)源標(biāo)識(shí)
package com.artisan.dynamicDB;
/**
*
*
* @ClassName: DynamicDataSourceHolder
*
* @Description:創(chuàng)建DynamicDataSourceHolder用于持有當(dāng)前線程中使用的數(shù)據(jù)源標(biāo)識(shí)
*
* @author: Mr.Yang
*
* @date: 2017年7月24日 下午8:23:50
*/
public class DynamicDataSourceHolder {
/**
* 數(shù)據(jù)源標(biāo)識(shí)保存在線程變量中,避免多線程操作數(shù)據(jù)源時(shí)互相干擾
*/
private static final ThreadLocal<String> dataSourceHolder = new ThreadLocal<String>();
/**
*
*
* @Title: setDataSource
*
* @Description: 設(shè)置數(shù)據(jù)源
*
* @param dataSource
*
* @return: void
*/
public static void setDataSource(String dataSource) {
dataSourceHolder.set(dataSource);
}
/**
*
*
* @Title: getDataSource
*
* @Description: 獲取數(shù)據(jù)源
*
* @return
*
* @return: String
*/
public static String getDataSource() {
return dataSourceHolder.get();
}
/**
*
*
* @Title: clearDataSource
*
* @Description: 清除數(shù)據(jù)源
*
*
* @return: void
*/
public static void clearDataSource() {
dataSourceHolder.remove();
}
}
步驟四 配置多個(gè)數(shù)據(jù)源和DynamicDataSource的bean
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<!-- 基類包,將標(biāo)注Spring注解的類自動(dòng)轉(zhuǎn)化Bean,同時(shí)完成Bean的注入 -->
<context:component-scan base-package="com.artisan"/>
<!-- 使用context命名空間,在xml文件中配置數(shù)據(jù)庫(kù)的properties文件 -->
<context:property-placeholder location="classpath:jdbc.properties" />
<!-- 配置數(shù)據(jù)源-->
<!-- 主站點(diǎn)的數(shù)據(jù)源 -->
<bean id="dataSourcePR" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="${jdbc.driverClassNamePR}"
p:url="${jdbc.urlPR}"
p:username="${jdbc.usernamePR}"
p:password="${jdbc.passwordPR}" />
<!-- 備用站點(diǎn)的數(shù)據(jù)源 -->
<bean id="dataSourceDR" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="${jdbc.driverClassNameDR}"
p:url="${jdbc.urlDR}"
p:username="${jdbc.usernameDR}"
p:password="${jdbc.passwordDR}" />
<!-- 主站點(diǎn)cc實(shí)例數(shù)據(jù)源 -->
<bean id="dataSourceCC" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="${jdbc.driverClassNameCC}"
p:url="${jdbc.urlCC}"
p:username="${jdbc.usernameCC}"
p:password="${jdbc.passwordCC}" />
<bean id="dynamicDataSource" class="com.artisan.dynamicDB.DynamicDataSource">
<property name="targetDataSources" ref="dynamicDatasourceMap" />
<!-- 默認(rèn)數(shù)據(jù)源 -->
<property name="defaultTargetDataSource" ref="dataSourcePR" />
</bean>
<!-- 指定lookupKey和與之對(duì)應(yīng)的數(shù)據(jù)源 -->
<util:map id="dynamicDatasourceMap" key-type="java.lang.String">
<entry key="dataSourcePR" value-ref="dataSourcePR" />
<entry key="dataSourceDR" value-ref="dataSourceDR" />
<entry key="dataSourceCC" value-ref="dataSourceCC" />
</util:map>
<!-- 配置Jdbc模板 JdbcTemplate使用動(dòng)態(tài)數(shù)據(jù)源的配置 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
p:dataSource-ref="dynamicDataSource" />
<!-- 配置數(shù)據(jù)源注解的攔截規(guī)則,比如攔截service層或者dao層的所有方法,這里攔截了com.artisan下的全部方法 -->
<bean id="dataSourceAspect" class="com.artisan.dynamicDB.DataSourceAspect" />
<aop:config>
<aop:aspect ref="dataSourceAspect">
<!-- 攔截所有XXX方法 -->
<aop:pointcut id="dataSourcePointcut" expression="execution(* com.artisan..*(..))"/>
<aop:before pointcut-ref="dataSourcePointcut" method="intercept" />
</aop:aspect>
</aop:config>
<!-- 配置事務(wù)管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dynamicDataSource" />
<!-- 通過(guò)AOP配置提供事務(wù)增強(qiáng),讓com.artisan包下所有Bean的所有方法擁有事務(wù) -->
<aop:config proxy-target-class="true">
<aop:pointcut id="serviceMethod"
expression="(execution(* com.artisan..*(..))) and (@annotation(org.springframework.transaction.annotation.Transactional))" />
<aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice" />
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" />
</tx:attributes>
</tx:advice>
</beans>
配置到這里,我們就可以使用多個(gè)數(shù)據(jù)源了,只需要在操作數(shù)據(jù)庫(kù)之前只要DynamicDataSourceHolder.setDataSource(“dataSourcePR”)即可切換到數(shù)據(jù)源dataSourcePR并對(duì)數(shù)據(jù)庫(kù)dataSourcePR進(jìn)行操作了。
問(wèn)題:每次使用都需要調(diào)用DynamicDataSourceHolder#setDataSource,十分繁瑣,并且難以維護(hù)。
我們可以通過(guò)Spring的AOP和注解, 直接通過(guò)注解的方式指定需要訪問(wèn)的數(shù)據(jù)源。 繼續(xù)改進(jìn)下吧
步驟五 定義名為@DataSource的注解
package com.artisan.dynamicDB;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
*
* @ClassName: DataSource
*
*
* @Description: 注解@DataSource既可以加在方法上,也可以加在接口或者接口的實(shí)現(xiàn)類上,優(yōu)先級(jí)別:方法>實(shí)現(xiàn)類>接口。
* 如果接口、接口實(shí)現(xiàn)類以及方法上分別加了@DataSource注解來(lái)指定數(shù)據(jù)源,則優(yōu)先以方法上指定的為準(zhǔn)。
*
* @author: Mr.Yang
*
* @date: 2017年7月24日 下午9:59:29
*/
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
// 和配置文件中 dynamicDatasourceMap中的key保持一致
public static String PR_RB = "dataSourcePR";
public static String DR_RB = "dataSourceDR";
public static String PR_CC = "dataSourceCC";
/**
*
*
* @Title: name
*
* @Description: 如果僅標(biāo)注@DataSource 默認(rèn)為PR_RB數(shù)據(jù)庫(kù)實(shí)例
*
* @return
*
* @return: String
*/
String name() default DataSource.PR_RB;
}
步驟六 定義AOP切面以便攔截所有帶有注解@DataSource的方法,取出注解的值作為數(shù)據(jù)源標(biāo)識(shí)放到DynamicDataSourceHolder的線程變量中
package com.artisan.dynamicDB;
import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
/**
*
*
* @ClassName: DataSourceAspect
*
* @Description:
* 定義AOP切面以便攔截所有帶有注解@DataSource的方法,取出注解的值作為數(shù)據(jù)源標(biāo)識(shí)放到DBContextHolder的線程變量中
*
* @author: Mr.Yang
*
* @date: 2017年7月25日 上午10:51:41
*/
public class DataSourceAspect {
/**
*
*
* @Title: intercept
*
* @Description: 攔截目標(biāo)方法,獲取由@DataSource指定的數(shù)據(jù)源標(biāo)識(shí),設(shè)置到線程存儲(chǔ)中以便切換數(shù)據(jù)源
*
* @param point
* @throws Exception
*
* @return: void
*/
public void intercept(JoinPoint point) throws Exception {
Class<?> target = point.getTarget().getClass();
MethodSignature signature = (MethodSignature) point.getSignature();
// 默認(rèn)使用目標(biāo)類型的注解,如果沒有則使用其實(shí)現(xiàn)接口的注解
for (Class<?> clazz : target.getInterfaces()) {
resolveDataSource(clazz, signature.getMethod());
}
resolveDataSource(target, signature.getMethod());
}
/**
*
*
* @Title: resolveDataSource
*
* @Description: 提取目標(biāo)對(duì)象方法注解和類型注解中的數(shù)據(jù)源標(biāo)識(shí)
*
* @param clazz
* @param method
*
* @return: void
*/
private void resolveDataSource(Class<?> clazz, Method method) {
try {
Class<?>[] types = method.getParameterTypes();
// 默認(rèn)使用類型注解
if (clazz.isAnnotationPresent(DataSource.class)) {
DataSource source = clazz.getAnnotation(DataSource.class);
DynamicDataSourceHolder.setDataSource(source.name());
}
// 方法注解可以覆蓋類型注解
Method m = clazz.getMethod(method.getName(), types);
if (m != null && m.isAnnotationPresent(DataSource.class)) {
DataSource source = m.getAnnotation(DataSource.class);
DynamicDataSourceHolder.setDataSource(source.name());
}
} catch (Exception e) {
System.out.println(clazz + ":" + e.getMessage());
}
}
}
步驟七 在spring配置文件中配置攔截規(guī)則
<!-- 配置數(shù)據(jù)源注解的攔截規(guī)則,比如攔截service層或者dao層的所有方法,這里攔截了com.artisan下的全部方法 --> <bean id="dataSourceAspect" class="com.artisan.dynamicDB.DataSourceAspect" /> <aop:config> <aop:aspect ref="dataSourceAspect"> <!-- 攔截所有XXX方法 --> <aop:pointcut id="dataSourcePointcut" expression="execution(* com.artisan..*(..))"/> <aop:before pointcut-ref="dataSourcePointcut" method="intercept" /> </aop:aspect> </aop:config>
步驟八 使用注解切換多數(shù)據(jù)源
ExtractDataService.java
package com.artisan.extractService;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.stereotype.Service;
import com.artisan.dynamicDB.DataSource;
/**
*
*
* @ClassName: ExtractDataService
*
* @Description: 業(yè)務(wù)類,這里暫時(shí)作為測(cè)試多數(shù)據(jù)源切換用
*
* @author: Mr.Yang
*
* @date: 2017年7月24日 下午9:07:38
*/
@Service
public class ExtractDataService {
private static final Logger logger = LogManager
.getLogger(ExtractDataService.class.getName());
private JdbcTemplate jdbcTemplate;
@Autowired
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
/**
*
*
* @Title: selectDataFromPR
*
* @Description:
*
*
* @return: void
*/
@DataSource(name = DataSource.PR_RB)
public void selectDataFromPR_RB() {
String sql = "select subs_id from owe_event_charge where event_inst_id = 10229001 ";
jdbcTemplate.query(sql, new RowCallbackHandler() {
@Override
public void processRow(ResultSet rs) throws SQLException {
logger.info(rs.getInt("subs_id"));
}
});
}
@DataSource(name = DataSource.DR_RB)
public void selectDataFromDR_RB() {
// 改為通過(guò)注解指定DB
// DynamicDataSourceHolder.setDataSource(DBContextHolder.DATA_SOURCE_DR);
String sql = " select a.task_comments from nm_task_type a where a.task_name = 'ALARM_LOG_LEVEL' ";
jdbcTemplate.query(sql, new RowCallbackHandler() {
@Override
public void processRow(ResultSet rs) throws SQLException {
logger.info(rs.getString("task_comments"));
}
});
}
@DataSource(name = DataSource.PR_CC)
public void selectDataFromPR_CC() {
// DBContextHolder.setDataSource(DBContextHolder.DATA_SOURCE_CC);
String sql = "select acc_nbr from acc_nbr where acc_nbr_id = 82233858 ";
jdbcTemplate.query(sql, new RowCallbackHandler() {
@Override
public void processRow(ResultSet rs) throws SQLException {
logger.info(rs.getString("acc_nbr"));
}
});
}
}
步驟九 測(cè)試
package com.artisan;
import java.io.IOException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import com.artisan.extractService.ExtractDataService;
/**
*
*
* @ClassName: App
*
* @Description: 入口類
*
* @author: Mr.Yang
*
* @date: 2017年7月24日 下午8:50:25
*/
public class App {
public static void main(String[] args) {
try {
// 加載日志框架 log4j2
LoggerContext context = (LoggerContext) LogManager
.getContext(false);
ResourceLoader loader = new PathMatchingResourcePatternResolver();
Resource resource = loader.getResource("classpath:log4j2.xml");
context.setConfigLocation(resource.getFile().toURI());
// 加載spring配置信息
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"classpath:spring-context.xml");
// 從容器中獲取Bean
ExtractDataService service = ctx.getBean("extractDataService",
ExtractDataService.class);
// 從PR的RB實(shí)例中獲取數(shù)據(jù)
service.selectDataFromPR_RB();
// 從DR的RB實(shí)例中獲取數(shù)據(jù)
service.selectDataFromDR_RB();
// 從PR的CC實(shí)例中獲取數(shù)據(jù)
service.selectDataFromPR_CC();
} catch (IOException e) {
e.printStackTrace();
}
}
}
其他代碼
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- log4j2使用說(shuō)明:
使用方式如下:
private static final Logger logger = LogManager.getLogger(實(shí)際類名.class.getName());
-->
<!--日志級(jí)別以及優(yōu)先級(jí)排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration后面的status,這個(gè)用于設(shè)置log4j2自身內(nèi)部的信息輸出,可以不設(shè)置,當(dāng)設(shè)置成trace時(shí),你會(huì)看到log4j2內(nèi)部各種詳細(xì)輸出-->
<!--monitorInterval:Log4j能夠自動(dòng)檢測(cè)修改配置 文件和重新配置本身,設(shè)置間隔秒數(shù)-->
<configuration status="info" monitorInterval="180">
<!-- 文件路徑和文件名稱,方便后面引用 -->
<Properties>
<Property name="backupFilePatch">D:/workspace/workspace-sts/backupOracle/log/</Property>
<Property name="fileName">backupOracle.log</Property>
</Properties>
<!--先定義所有的appender-->
<appenders>
<!--這個(gè)輸出控制臺(tái)的配置-->
<Console name="Console" target="SYSTEM_OUT">
<!--控制臺(tái)只輸出level及以上級(jí)別的信息(onMatch),其他的直接拒絕(onMismatch)-->
<ThresholdFilter level="trace" onMatch="ACCEPT" onMismatch="DENY" />
<!-- 輸出日志的格式-->
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n" />
</Console>
<!--這個(gè)會(huì)打印出所有的信息,每次大小超過(guò)size,則這size大小的日志會(huì)自動(dòng)存入按年份-月份建立的文件夾下面并進(jìn)行壓縮,作為存檔-->
<RollingFile name="RollingFile" fileName="${backupFilePatch}${fileName}"
filePattern="${backupFilePatch}$${date:yyyy-MM}/app-%d{yyyyMMddHHmmssSSS}.log.gz">
<PatternLayout
pattern="%d{yyyy.MM.dd 'at' HH:mm:ss.SSS z} %-5level %class{36} %L %M - %msg%xEx%n" />
<!-- 日志文件大小 -->
<SizeBasedTriggeringPolicy size="20MB" />
<!-- 最多保留文件數(shù) DefaultRolloverStrategy屬性如不設(shè)置,則默認(rèn)為最多同一文件夾下7個(gè)文件,這里設(shè)置了20 -->
<DefaultRolloverStrategy max="20"/>
</RollingFile>
</appenders>
<!--然后定義logger,只有定義了logger并引入的appender,appender才會(huì)生效-->
<loggers>
<!--過(guò)濾掉spring和mybatis的一些無(wú)用的DEBUG信息-->
<logger name="org.springframework" level="INFO"></logger>
<logger name="org.mybatis" level="INFO"></logger>
<root level="trace">
<appender-ref ref="RollingFile"/>
<appender-ref ref="Console"/>
</root>
</loggers>
</configuration>
jdbc.properties
########################## ## ## ## dbcp datasource pool ,basic configuration first. ## the other parameters keep default for now , you can change them if you want ## ## ########################## #Database in Lapaz jdbc.driverClassNamePR=oracle.jdbc.driver.OracleDriver jdbc.urlPR=jdbc:oracle:thin:@172.25.243.4:1521:xx jdbc.usernamePR=xxx jdbc.passwordPR=xxxxxxxx #Database in Scluz jdbc.driverClassNameDR=oracle.jdbc.driver.OracleDriver jdbc.urlDR=jdbc:oracle:thin:@172.25.246.1:1521:xx jdbc.usernameDR=xxx jdbc.passwordDR=xxxxxxx #Database in Lapaz jdbc.driverClassNameCC=oracle.jdbc.driver.OracleDriver jdbc.urlCC=jdbc:oracle:thin:@172.25.243.3:1521:xx jdbc.usernameCC=xxx jdbc.passwordCC=xxxxxx
運(yùn)行結(jié)果:

代碼
https://github.com/yangshangwei/DynamicDataSource
以上這篇Spring-基于Spring使用自定義注解及Aspect實(shí)現(xiàn)數(shù)據(jù)庫(kù)切換操作就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java利用 Exchanger 實(shí)現(xiàn)游戲中交換裝備
JDK 1.5 開始 JUC 包下提供的 Exchanger 類可用于兩個(gè)線程之間交換信息。下面我們就來(lái)看看Java是如何利用Exchanger一行代碼實(shí)現(xiàn)游戲中交換裝備的2021-09-09
Spring boot集成spring session實(shí)現(xiàn)session共享的方法
這篇文章主要介紹了Spring boot集成spring session實(shí)現(xiàn)session共享的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-06-06
Spring?Boot多個(gè)定時(shí)任務(wù)阻塞問(wèn)題的解決方法
在日常的項(xiàng)目開發(fā)中,往往會(huì)涉及到一些需要做到定時(shí)執(zhí)行的代碼,下面這篇文章主要給大家介紹了關(guān)于Spring?Boot多個(gè)定時(shí)任務(wù)阻塞問(wèn)題的解決方法,需要的朋友可以參考下2022-01-01
win10 eclipse配置環(huán)境變量的教程圖解
本文通過(guò)圖文并茂的形式給大家介紹了win10 eclipse配置環(huán)境變量的方法,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2018-07-07
java實(shí)現(xiàn)自動(dòng)回復(fù)聊天機(jī)器人
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)自動(dòng)回復(fù)聊天機(jī)器人,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-08-08
Spring如何基于注解顯式實(shí)現(xiàn)自動(dòng)裝配
這篇文章主要介紹了Spring如何基于注解顯式實(shí)現(xiàn)自動(dòng)裝配,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08

