package org.springboot.sample.datasource;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.Resource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.core.JdbcTemplate;
/**
* 注册动态数据源
*
* @author 单红宇(365384722)
* @myblog http://blog.csdn.net/catoop/
* @create 2016年1月23日
*/
//@Configuration
@Deprecated// 改用DynamicDataSourceRegister类
public class ConfigurationDynamicDataSourceRegister
implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, EnvironmentAware {
// 如配置文件中未指定数据源类型,使用该默认值
private static final Object DATASOURCE_TYPE_DEFAULT = "org.apache.tomcat.jdbc.pool.DataSource";
// private static final Object DATASOURCE_TYPE_DEFAULT = "com.zaxxer.hikari.HikariDataSource";
private ApplicationContext applicationContext;
// 存放DataSource配置的集合,模型<dataSourceName,dataSourceMap>
private Map<String, Map<String, Object>> dataSourceInfoMap = new HashMap<>();
@Resource(name="dataSource")
private javax.sql.DataSource dataSource;
/**
* 获得ApplicationContext
*
* @param event
* @author SHANHY
* @create 2016年1月23日
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
/**
* 监听容器刷新事件 OR Start Event
*
* @param event
* @author SHANHY
* @create 2016年1月23日
*/
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
registerDynamicDataSource();
}
/**
* 注册动态数据源
*
* @author SHANHY
* @create 2016年1月23日
*/
private void registerDynamicDataSource() {
// 把数据源bean注册到容器中
addBeanToApplication(dataSourceInfoMap);
}
/**
* 功能说明:根据DataSource创建bean并注册到容器中
*
* @param acf
* @param customDataSourceMap
*/
private void addBeanToApplication(Map<String, Map<String, Object>> customDataSourceMap) {
DefaultListableBeanFactory acf = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
BeanDefinitionBuilder bdb;
Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
// 将默认数据源放入 targetDataSources map中
targetDataSources.put("dataSource", dataSource);
DynamicDataSourceContextHolder.dataSourceIds.add("dataSource");
// 根据数据源得到数据,动态创建数据源bean 并将bean注册到applicationContext中去
Map<String, Object> dsMap = null;
for (Entry<String, Map<String, Object>> entry : customDataSourceMap.entrySet()) {
// bean ID
String key = entry.getKey();
dsMap = entry.getValue();
Object type = dsMap.get("type");
if (type == null)
type = DATASOURCE_TYPE_DEFAULT;// 默认DataSource
// 创建bean
bdb = BeanDefinitionBuilder.rootBeanDefinition(type.toString());
bdb.getBeanDefinition().setAttribute("id", key);
bdb.addPropertyValue("driverClassName", dsMap.get("driver-class-name"));
bdb.addPropertyValue("url", dsMap.get("url"));
bdb.addPropertyValue("username", dsMap.get("username"));
bdb.addPropertyValue("password", dsMap.get("password"));
// 注册bean
acf.registerBeanDefinition(key, bdb.getBeanDefinition());
// 放入map中,注意一定是刚才创建bean对象
targetDataSources.put(key, applicationContext.getBean(key));
DynamicDataSourceContextHolder.dataSourceIds.add(key);
}
bdb = BeanDefinitionBuilder.rootBeanDefinition(DynamicDataSource.class);
bdb.getBeanDefinition().setAttribute("id", "dynamicDataSource");
bdb.addPropertyValue("defaultTargetDataSource", dataSource);
bdb.addPropertyValue("targetDataSources", targetDataSources);
// 注册Bean
acf.registerBeanDefinition("dynamicDataSource", bdb.getBeanDefinition());
// // 必须重新初始化 AbstractRoutingDataSource 中的 resolvedDataSources,动态切换才会生效
DynamicDataSource dynamicDataSource = (DynamicDataSource)applicationContext.getBean("dynamicDataSource");
dynamicDataSource.afterPropertiesSet();
autowiredDynamicDataSource(dynamicDataSource);
}
/**
* 注入动态数据源到jdbcTemplate、sqlSessoinTemplate
*
* @author SHANHY
* @create 2016年1月24日
*/
private void autowiredDynamicDataSource(DynamicDataSource dynamicDataSource){
//>>>>>>>>>>>>>>>>> JdbcTemplate <<<<<<<<<<<<<<<<<//
// 读取jdbcTemplate,设置dynamicDataSource为它的dataSource
JdbcTemplate jdbcTemplate = (JdbcTemplate)applicationContext.getBean(JdbcTemplate.class);
jdbcTemplate.setDataSource(dynamicDataSource);
jdbcTemplate.afterPropertiesSet();
//>>>>>>>>>>>>>>>>> SqlSessionTemplate <<<<<<<<<<<<<<<<<//
SqlSessionFactory sqlSessionFactory = (SqlSessionFactory)applicationContext.getBean(SqlSessionFactory.class);
org.apache.ibatis.mapping.Environment myBatisEnvironment = sqlSessionFactory.getConfiguration().getEnvironment();
sqlSessionFactory.getConfiguration().setEnvironment(new org.apache.ibatis.mapping.Environment(myBatisEnvironment.getId(), myBatisEnvironment.getTransactionFactory(), dynamicDataSource));
}
/**
* 加载多数据源配置
*/
@Override
public void setEnvironment(Environment env) {
RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "custom.datasource.");
String dsPrefixs = propertyResolver.getProperty("names");
for (String dsPrefix : dsPrefixs.split(",")) {// 多个数据源
Map<String, Object> dsMap = propertyResolver.getSubProperties(dsPrefix + ".");
dataSourceInfoMap.put(dsPrefix, dsMap);
}
}
}