SpringBoot多数据源改造(一)

     今天做一个需求,业务项目需要访问另一个项目的数据库。

     常用两种方案:

         1、另一个项目提供一个RestFul API,供调用方通过feign或其它httpClient等方式来访问。

         2、项目中通过配置多数据源访问另一个项目库,当然必须有访问权限。

    经过对比分析,决定采用第二种方案,原因:一方面,有访问另一个数据源的权限。另一方面,减少一层中间API服务可用性的依赖。

   于是开始动手:

   第一步,增加新数据源的配置类

@Configuration
@MapperScan(basePackages = {"com.XXX.ecc.YYY.dao"}, sqlSessionTemplateRef = "sqlSessionTemplate2")
public class DataSource2Config {

/**
* 创建datasource对象
* @return
*/
@Bean(name = "dataSource2")
@ConfigurationProperties(prefix = "YYY.datasource.prefix")// prefix值必须是application.properteis中对应属性的前缀
public DataSource dataSource2() {
return DataSourceBuilder.create().build();
}

/**
* 创建sql工程
* @param dataSource
* @return
* @throws Exception
*/
@Bean(name = "sqlSessionFactory2")
public SqlSessionFactory sqlSessionFactory2(@Qualifier("dataSource2") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
//对应mybatis.type-aliases-package配置
bean.setTypeAliasesPackage("com.XXX.ecc.cloudbiz.domain");
//对应mybatis.mapper-locations配置
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:YYY_sqlmap/**/*.xml"));
//开启驼峰映射
bean.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);
return bean.getObject();
}

/**
* 配置事务管理
* @param dataSource
* @return
*/
@Bean(name = "transactionManager2")
public DataSourceTransactionManager transactionManager2(@Qualifier("dataSource2") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}

/**
* sqlSession模版,用于配置自动扫描pojo实体类
* @param sqlSessionFactory
* @return
* @throws Exception
*/
@Bean(name = "sqlSessionTemplate2")
public SqlSessionTemplate sqlSessionTemplate2(@Qualifier("sqlSessionFactory2") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}

第二步:
在resources下增加
YYY_sqlmap文件夹,并且创建YYYMapper.xml,在@MapperScan(basePackages = {"com.XXX.ecc.YYY.dao"}指定的包下,创建YYYMapper.java文件。

第三步:改造原有数据源:增加MapperScan注解,增加事务配置及sessionFactory方法,并在事务、datasource、sessionfactory的方法加上@Primary注解,做为主数据源
@Configuration
@MapperScan(basePackages = {"com.XXX.ecc.zzz.dao"}, sqlSessionTemplateRef = "sqlSessionTemplate")
public class DruidConfig {

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

@Value("${spring.datasource.url}")
private String dbUrl;

@Value("${spring.datasource.username}")
private String username;

@Value("${spring.datasource.password}")
private String password;

@Value("${spring.datasource.driver-class-name}")
private String driverClassName;

@Value("${spring.datasource.initialSize}")
private int initialSize;

@Value("${spring.datasource.minIdle}")
private int minIdle;

@Value("${spring.datasource.maxActive}")
private int maxActive;

@Value("${spring.datasource.maxWait}")
private int maxWait;

@Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
private int timeBetweenEvictionRunsMillis;

@Value("${spring.datasource.minEvictableIdleTimeMillis}")
private int minEvictableIdleTimeMillis;

@Value("${spring.datasource.validationQuery}")
private String validationQuery;

@Value("${spring.datasource.testWhileIdle}")
private boolean testWhileIdle;

@Value("${spring.datasource.testOnBorrow}")
private boolean testOnBorrow;

@Value("${spring.datasource.testOnReturn}")
private boolean testOnReturn;

@Value("${spring.datasource.poolPreparedStatements}")
private boolean poolPreparedStatements;

@Value("${spring.datasource.filters}")
private String filters;

@Value("${spring.datasource.loginUserName}")
private String loginUserName;

@Value("${spring.datasource.loginUserPassword}")
private String loginUserPassword;

@Value("${spring.datasource.pwdDecrypt:config.decrypt=true}")
private Properties pwdDecryptProperties;
@Value("${spring.datasource.publicKey:''}")
private String publicKey;

@Value("${spring.datasource.allow}")
private String allowIp;
@Value("${spring.datasource.deny}")
private String denyIp;
@Bean
public ServletRegistrationBean druidServlet() {
ServletRegistrationBean reg = new ServletRegistrationBean();
reg.setServlet(new StatViewServlet());
reg.addUrlMappings("/druid/*");
//IP白名单
reg.addInitParameter("allow",allowIp);
//IP黑名单
reg.addInitParameter("deny",denyIp);
//控制台管理用户
reg.addInitParameter("loginUsername", loginUserName);
reg.addInitParameter("loginPassword", loginUserPassword);
return reg;
}

@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new WebStatFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
filterRegistrationBean.addInitParameter("profileEnable", "true");
filterRegistrationBean.addInitParameter("principalCookieName", "USER_COOKIE");
filterRegistrationBean.addInitParameter("principalSessionName", "USER_SESSION");
return filterRegistrationBean;
}

@Bean(name = "dataSource")
@Primary
public DataSource druidDataSource(){
DruidDataSource datasource = new DruidDataSource();

datasource.setUrl(this.dbUrl);
datasource.setUsername(username);
datasource.setPassword(password);
datasource.setDriverClassName(driverClassName);
datasource.setInitialSize(initialSize);
datasource.setMinIdle(minIdle);
datasource.setMaxActive(maxActive);
datasource.setMaxWait(maxWait);
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
datasource.setValidationQuery(validationQuery);
datasource.setTestWhileIdle(testWhileIdle);
datasource.setTestOnBorrow(testOnBorrow);
datasource.setTestOnReturn(testOnReturn);
datasource.setPoolPreparedStatements(poolPreparedStatements);
try {
datasource.setFilters(filters);
pwdDecryptProperties.setProperty("config.decrypt.key",publicKey);
datasource.setConnectProperties(pwdDecryptProperties);
} catch (SQLException e) {
logger.error("druid configuration initialization filter", e);
}
return datasource;
}

/**
* 创建sql工程
* @param dataSource
* @return
* @throws Exception
*/
@Bean(name = "sqlSessionFactory")
@Primary
public SqlSessionFactory sqlSessionFactory2(@Qualifier("dataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
//对应mybatis.type-aliases-package配置
bean.setTypeAliasesPackage("com.XXX.ecc.zzz.domain");
//对应mybatis.mapper-locations配置
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:sqlmap/**/*.xml"));
//开启驼峰映射
bean.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);
return bean.getObject();
}

/**
* 配置事务管理
* @param dataSource
* @return
*/
@Bean(name = "transactionManager")
@Primary
public DataSourceTransactionManager transactionManager2(@Qualifier("dataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}

/**
* sqlSession模版,用于配置自动扫描pojo实体类
* @param sqlSessionFactory
* @return
* @throws Exception
*/
@Bean(name = "sqlSessionTemplate")
@Primary
public SqlSessionTemplate sqlSessionTemplate2(@Qualifier("sqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
第四步:在项目启动类上去掉@MapperScan注解

至此,配置完成,编译启动测试即可。

注意事项
1、
@Primary在主数据源要配置上,否则在@Autowired时会出错或注入非期待的数据源
2、@Qualifier:当一个接口有多个实现类的时候使用,通过指定名称的注入,


 
 
posted @ 2019-05-26 00:09  xuzhujack  阅读(800)  评论(0编辑  收藏  举报
;