spring boot之多数据源

来源:互联网 发布:知乎眼睛漂亮的女孩 编辑:程序博客网 时间:2024/06/15 22:29

这个完全是意外收获,看着挺好玩的,就配着玩一下,
话不多说,开始搞,基本的spring boot框架不动,然后在框架上添加东西,我这儿使用mysql和国产oscar数据库开发
注意添加数据库驱动包的依赖
先来application.properties:

server.port=2601spring.application.name=iam-storagespring.datasource.url=jdbc:mysql://localhost:3306/testspring.datasource.username=rootspring.datasource.password=123456spring.datasource.driver-class-name=com.mysql.jdbc.Drivercustom.datasource.names=ds1,ds2custom.datasource.ds1.driver-class-name=com.oscar.Drivercustom.datasource.ds1.url=jdbc:oscar://localhost:2003/osrdbcustom.datasource.ds1.username=sysdbacustom.datasource.ds1.password=123456custom.datasource.ds2.driver-class-name=com.oscar.Drivercustom.datasource.ds2.url=jdbc:oscar://localhost:2003/metacustom.datasource.ds2.username=sysdbacustom.datasource.ds2.password=123456mybatis.mapperLocations: classpath:/mybatis/*.xml

最上边是我们默认的我们添加了一个ds1,ds2;我们在项目中用到了默认的数据库mysql和添加的ds1;

先说最后如何用吧
假如用mybatis来查询的话,在service上添加这个注解,其它不变;(不能在mapper的接口上加哦)

    @TargetDataSource(name="ds1")    public String getMsg4() {        // TODO Auto-generated method stub        return Integer.toString(testMapper.getMsg4());    }

用jdbcTemplate的话

@TargetDataSource(name="ds1")    @SuppressWarnings("unchecked")    public String getMsg(){        return jdbcTemplate.query("select * from table2",new ResultSetExtractor() {              public Object extractData(ResultSet rs) throws SQLException, DataAccessException {                  int id = 0 ;                while (rs.next()) {                       id = rs.getInt("id");                }                return  Integer.toString(id);              }          });    }

搞定使用方法了,我们现在再回头来看为什么能成功呢,一切都应该我们加的一个bean ,我们在启动类上引用了一个import中的类;

@ComponentScan@MapperScan("org.test2.mapper")@Import({DynamicDataSourceRegister.class})@SpringBootApplicationpublic class Application {    public static void main(String args[]){        SpringApplication.run(Application.class);    }}

我们看看生成这个注册类的其它配置类
这里写图片描述
注意比之前添加一个依赖:

          <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-aop</artifactId>        </dependency>
public class DynamicDataSource extends AbstractRoutingDataSource {    @Override    protected Object determineCurrentLookupKey() {        return DynamicDataSourceContextHolder.getDataSourceType();    }}
@Aspect@Order(-1)// 保证该AOP在@Transactional之前执行@Componentpublic class DynamicDataSourceAspect {    private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspect.class);    @Before("@annotation(ds)")    public void changeDataSource(JoinPoint point, TargetDataSource ds) throws Throwable {        String dsId = ds.name();        if (!DynamicDataSourceContextHolder.containsDataSource(dsId)) {            logger.error("数据源[{}]不存在,使用默认数据源 > {}", ds.name(), point.getSignature());        } else {            logger.debug("Use DataSource : {} > {}", ds.name(), point.getSignature());            DynamicDataSourceContextHolder.setDataSourceType(ds.name());        }    }    @After("@annotation(ds)")    public void restoreDataSource(JoinPoint point, TargetDataSource ds) {        logger.debug("Revert DataSource : {} > {}", ds.name(), point.getSignature());        DynamicDataSourceContextHolder.clearDataSourceType();    }}
public class DynamicDataSourceContextHolder {    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();    public static List<String> dataSourceIds = new ArrayList<>();    public static void setDataSourceType(String dataSourceType) {        contextHolder.set(dataSourceType);    }    public static String getDataSourceType() {        return contextHolder.get();    }    public static void clearDataSourceType() {        contextHolder.remove();    }    /**     * 判断指定DataSrouce当前是否存在     *     * @param dataSourceId     * @return     */    public static boolean containsDataSource(String dataSourceId){        return dataSourceIds.contains(dataSourceId);    }}
/** * 动态数据源注册<br/> * 启动动态数据源请在启动类中(如SpringBootSampleApplication) * 添加 @Import(DynamicDataSourceRegister.class) */public class DynamicDataSourceRegister        implements ImportBeanDefinitionRegistrar, EnvironmentAware {    private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceRegister.class);    private ConversionService conversionService = new DefaultConversionService();     private PropertyValues dataSourcePropertyValues;    // 如配置文件中未指定数据源类型,使用该默认值    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 DataSource defaultDataSource;    private Map<String, DataSource> customDataSources = new HashMap<>();    @Override    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {        Map<Object, Object> targetDataSources = new HashMap<Object, Object>();        // 将主数据源添加到更多数据源中        targetDataSources.put("dataSource", defaultDataSource);        DynamicDataSourceContextHolder.dataSourceIds.add("dataSource");        // 添加更多数据源        targetDataSources.putAll(customDataSources);        for (String key : customDataSources.keySet()) {            DynamicDataSourceContextHolder.dataSourceIds.add(key);        }        // 创建DynamicDataSource        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();        beanDefinition.setBeanClass(DynamicDataSource.class);        beanDefinition.setSynthetic(true);        MutablePropertyValues mpv = beanDefinition.getPropertyValues();        mpv.addPropertyValue("defaultTargetDataSource", defaultDataSource);        mpv.addPropertyValue("targetDataSources", targetDataSources);        registry.registerBeanDefinition("dataSource", beanDefinition);        logger.info("Dynamic DataSource Registry");    }    /**     * 创建DataSource     *     * @param type     * @param driverClassName     * @param url     * @param username     * @param password     * @return     */    @SuppressWarnings("unchecked")    public DataSource buildDataSource(Map<String, Object> dsMap) {        try {            Object type = dsMap.get("type");            if (type == null)                type = DATASOURCE_TYPE_DEFAULT;// 默认DataSource            Class<? extends DataSource> dataSourceType;            dataSourceType = (Class<? extends DataSource>) Class.forName((String) type);            String driverClassName = dsMap.get("driver-class-name").toString();            String url = dsMap.get("url").toString();            String username = dsMap.get("username").toString();            String password = dsMap.get("password").toString();            DataSourceBuilder factory = DataSourceBuilder.create().driverClassName(driverClassName).url(url)                    .username(username).password(password).type(dataSourceType);            return factory.build();        } catch (ClassNotFoundException e) {            e.printStackTrace();        }        return null;    }    /**     * 加载多数据源配置     */    @Override    public void setEnvironment(Environment env) {        initDefaultDataSource(env);        initCustomDataSources(env);    }    /**     * 初始化主数据源     */    private void initDefaultDataSource(Environment env) {        // 读取主数据源        RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "spring.datasource.");        Map<String, Object> dsMap = new HashMap<>();        dsMap.put("type", propertyResolver.getProperty("type"));        dsMap.put("driver-class-name", propertyResolver.getProperty("driver-class-name"));        dsMap.put("url", propertyResolver.getProperty("url"));        dsMap.put("username", propertyResolver.getProperty("username"));        dsMap.put("password", propertyResolver.getProperty("password"));        defaultDataSource = buildDataSource(dsMap);        dataBinder(defaultDataSource, env);    }    /**     * 为DataSource绑定更多数据     *     * @param dataSource     * @param env     */    private void dataBinder(DataSource dataSource, Environment env){        RelaxedDataBinder dataBinder = new RelaxedDataBinder(dataSource);        //dataBinder.setValidator(new LocalValidatorFactory().run(this.applicationContext));        dataBinder.setConversionService(conversionService);        dataBinder.setIgnoreNestedProperties(false);//false        dataBinder.setIgnoreInvalidFields(false);//false        dataBinder.setIgnoreUnknownFields(true);//true        if(dataSourcePropertyValues == null){            Map<String, Object> rpr = new RelaxedPropertyResolver(env, "spring.datasource").getSubProperties(".");            Map<String, Object> values = new HashMap<>(rpr);            // 排除已经设置的属性            values.remove("type");            values.remove("driver-class-name");            values.remove("url");            values.remove("username");            values.remove("password");            dataSourcePropertyValues = new MutablePropertyValues(values);        }        dataBinder.bind(dataSourcePropertyValues);    }    /**     * 初始化更多数据源     *     * @author SHANHY     * @create 2016年1月24日     */    private void initCustomDataSources(Environment env) {        // 读取配置文件获取更多数据源,也可以通过defaultDataSource读取数据库获取更多数据源        RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "custom.datasource.");        String dsPrefixs = propertyResolver.getProperty("names");        for (String dsPrefix : dsPrefixs.split(",")) {// 多个数据源            Map<String, Object> dsMap = propertyResolver.getSubProperties(dsPrefix + ".");            DataSource ds = buildDataSource(dsMap);            customDataSources.put(dsPrefix, ds);            dataBinder(ds, env);        }    }}
@Target({ ElementType.METHOD, ElementType.TYPE })@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface TargetDataSource {    String name();}

好了,大功告成,试着运行一下吧!

test2项目就是配置多数据源的
下载地址:http://download.csdn.net/download/u013289746/9947649