Spring-基于Spring使用自定义注解及Aspect实现数据库

家电修理 2023-07-16 19:16www.caominkang.com电器维修

实现思路

重写Spring的AbstractRoutingDataSource抽象类的determineCurrentLookupKey方法。

我们来看下Spring-AbstractRoutingDataSource的源码

AbstractRoutingDataSource获取数据源之前会先调用determineCurrentLookupKey方法查找当前的lookupKey。

Object lookupKey = determineCurrentLookupKey();
DataSource dataSource = this.resolvedDataSources.get(lookupKey);
.......
return dataSource;

lookupKey为数据源标识,通过重写这个查找数据源标识的方法就可以让spring切换到指定的数据源.

从变量定义中可以知道resolvedDataSources为Map类型的对象。

private Map resolvedDataSources;

示例

步骤一 新建Maven工程

依赖如下 pom.xml


	4.0.0

	.artisan
	dynamicDataSource
	0.0.1-SNAPSHOT
	jar

	dynamicDataSource
	http://maven.apache.

	
		UTF-8
		UTF-8
		4.3.9.RELEASE
		3.1.0
		1.8.1
		1.4
		8.1.8.v20121106
		1.2.17
		2.8.2
		6.8.7
		11.2.0.4.0
		1.2
	

	
		
		
			.springframeork
			spring-beans
			${spring.version}
		
		
			.springframeork
			spring-context
			${spring.version}
		
		
			.springframeork
			spring-context-support
			${spring.version}
		
		
			.springframeork
			spring-jdbc
			${spring.version}
		
		
			.springframeork
			spring-ebmvc
			${spring.version}
		

		
			mons-dbcp
			mons-dbcp
			${mons-dbcp.version}
		


		
			.aspectj
			aspectjeaver
			${aspectj.version}
		


		
			.testng
			testng
			${testng.version}
			test
		
		
			.springframeork
			spring-test
			${spring.version}
			test
		

		
		
			.oracle
			ojdbc6
			${oracle.version}
		

		
			.testng
			testng
			${testng.version}
			test
		

		
			.springframeork
			spring-test
			${spring.version}
			test
		
		
		
			.apache.logging.log4j
			log4j-api
			${log4j2.version}
		
		
			.apache.logging.log4j
			log4j-core
			${log4j2.version}
		
		
	

	
		
		
			
				.apache.maven.plugins
				maven-piler-plugin
				3.1
				
					1.7
					1.7
				
			
		
	

步骤二 继承AbstractRoutingDataSource并重写determineCurrentLookupKey方法获取特定数据源

package .artisan.dynamicDB;

import .springframeork.jdbc.datasource.lookup.AbstractRoutingDataSource;


public class DynamicDataSource extends AbstractRoutingDataSource {

	@Override
	protected Object determineCurrentLookupKey() {
		return DynamicDataSourceHolder.getDataSource();
	}
}

步骤三 创建DynamicDataSourceHolder用于持有当前线程中使用的数据源标识

package .artisan.dynamicDB;


public class DynamicDataSourceHolder {

 
 private static final ThreadLocal dataSourceHolder = ne ThreadLocal();

 
 public static void setDataSource(String dataSource) {
 dataSourceHolder.set(dataSource);
 }

 
 public static String getDataSource() {
 return dataSourceHolder.get();
 }

 
 public static void clearDataSource() {
 dataSourceHolder.remove();
 }
}

步骤四 配置多个数据源和DynamicDataSource的bean



 
 
 
 
 
 
 
  
 
 
 
 
 
  
 
 
 


 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  
 
 
  
  
  
  
  
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

配置到这里,我们就可以使用多个数据源了,只需要在操作数据库之前只要DynamicDataSourceHolder.setDataSource(“dataSourcePR”)即可切换到数据源dataSourcePR并对数据库dataSourcePR进行操作了。

问题每次使用都需要调用DynamicDataSourceHolder#setDataSource,十分繁琐,并且难以维护。

我们可以通过Spring的AOP和注解, 直接通过注解的方式指定需要访问的数据源。 继续改进下吧

步骤五 定义名为@DataSource的注解

package .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;


@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";

 
 String name() default DataSource.PR_RB;

}

步骤六 定义AOP切面以便拦截所有带有注解@DataSource的方法,取出注解的值作为数据源标识放到DynamicDataSourceHolder的线程变量中

package .artisan.dynamicDB;
import java.lang.reflect.Method;
import .aspectj.lang.JoinPoint;
import .aspectj.lang.reflect.MethodSignature;


public class DataSourceAspect {

 
 public void intercept(JoinPoint point) thros Exception {
 Class target = point.getTarget().getClass();
 MethodSignature signature = (MethodSignature) point.getSignature();
 // 默认使用目标类型的注解,如果没有则使用其实现接口的注解
 for (Class clazz : target.getInterfaces()) {
 resolveDataSource(clazz, signature.getMethod());
 }
 resolveDataSource(target, signature.getMethod());
 }

 
 private void resolveDataSource(Class clazz, Method method) {
 try {
 Class[] types = method.getParameterTypes();
 // 默认使用类型注解
 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配置文件中配置拦截规则

  
 
 
  
  
  
  
  
 

步骤八 使用注解切换多数据源

ExtractDataService.java
package .artisan.extractService;
import java.sql.ResultSet;
import java.sql.SQLException;
import .apache.logging.log4j.LogManager;
import .apache.logging.log4j.Logger;
import .springframeork.beans.factory.annotation.Autoired;
import .springframeork.jdbc.core.JdbcTemplate;
import .springframeork.jdbc.core.RoCallbackHandler;
import .springframeork.stereotype.Service;

import .artisan.dynamicDB.DataSource;
@Service
public class ExtractDataService {

 private static final Logger logger = LogManager
 .getLogger(ExtractDataService.class.getName());

 private JdbcTemplate jdbcTemplate;

 @Autoired
 public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
 this.jdbcTemplate = jdbcTemplate;
 }

 
 @DataSource(name = DataSource.PR_RB)
 public void selectDataFromPR_RB() {
 String sql = "select subs_id from oe_event_charge here event_inst_id = 10229001 ";

 jdbcTemplate.query(sql, ne RoCallbackHandler() {

 @Override
 public void processRo(ResultSet rs) thros SQLException {
 logger.info(rs.getInt("subs_id"));
 }
 });
 }

 @DataSource(name = DataSource.DR_RB)
 public void selectDataFromDR_RB() {
 // 改为通过注解指定DB
 // DynamicDataSourceHolder.setDataSource(DBContextHolder.DATA_SOURCE_DR);
 String sql = " select a.task_ments from nm_task_type a here a.task_name = 'ALARM_LOG_LEVEL' ";
 jdbcTemplate.query(sql, ne RoCallbackHandler() {

 @Override
 public void processRo(ResultSet rs) thros SQLException {
 logger.info(rs.getString("task_ments"));
 }
 });
 }

 @DataSource(name = DataSource.PR_CC)
 public void selectDataFromPR_CC() {
 // DBContextHolder.setDataSource(DBContextHolder.DATA_SOURCE_CC);
 String sql = "select a_nbr from a_nbr here a_nbr_id = 82233858 ";
 jdbcTemplate.query(sql, ne RoCallbackHandler() {

 @Override
 public void processRo(ResultSet rs) thros SQLException {
 logger.info(rs.getString("a_nbr"));
 }
 });

 }
}

步骤九 测试

package .artisan;
import java.io.IOException;
import .apache.logging.log4j.LogManager;
import .apache.logging.log4j.core.LoggerContext;
import .springframeork.context.ApplicationContext;
import .springframeork.context.support.ClassPathXmlApplicationContext;
import .springframeork.core.io.Resource;
import .springframeork.core.io.ResourceLoader;
import .springframeork.core.io.support.PathMatchingResourcePatternResolver;

import .artisan.extractService.ExtractDataService;


public class App {
 public static void main(String[] args) {
 try {
 // 加载日志框架 log4j2
 LoggerContext context = (LoggerContext) LogManager
 .getContext(false);
 ResourceLoader loader = ne PathMatchingResourcePatternResolver();
 Resource resource = loader.getResource("classpath:log4j2.xml");

 context.setConfigLocation(resource.getFile().toURI());

 // 加载spring配置信息
 ApplicationContext ctx = ne ClassPathXmlApplicationContext(
 "classpath:spring-context.xml");
 // 从容器中获取Bean
 ExtractDataService service = ctx.getBean("extractDataService",
 ExtractDataService.class);
 // 从PR的RB实例中获取数据
 service.selectDataFromPR_RB();
 // 从DR的RB实例中获取数据
 service.selectDataFromDR_RB();
 // 从PR的CC实例中获取数据
 service.selectDataFromPR_CC();

 } catch (IOException e) {
 e.printStackTrace();
 }

 }
}

其他代码

log4j2.xml






 
 
 D:/orkspace/orkspace-sts/backupOracle/log/
 backupOracle.log
 
 
 
 
 
  
  
  
  
 
 
 
 
  
  
  
  
  
 
 
 
 
 
 
 
 
  
   
   
   
 

jdbc.properties

##########################
##
##
## dbcp datasource pool ,basic configuration first.
## the other parameters keep default for no , you can change them if you ant 
##
##
##########################

#Database in Lapaz
jdbc.driverClassNamePR=oracle.jdbc.driver.OracleDriver
jdbc.urlPR=jdbc:oracle:thin:@172.25.243.4:1521:xx
jdbc.usernamePR=xxx
jdbc.passordPR=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.passordDR=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.passordCC=xxxxxx

运行结果

代码

https://github./yangshangei/DynamicDataSource

以上这篇Spring-基于Spring使用自定义注解及Aspect实现数据库切换操作就是我分享给大家的全部内容了,电脑维修网希望能给大家一个参考,也电脑维修网希望大家多多支持考高分网。

Copyright © 2016-2025 www.caominkang.com 曹敏电脑维修网 版权所有 Power by