`
LynsaHuang
  • 浏览: 45677 次
  • 性别: Icon_minigender_2
  • 来自: 北京
社区版块
存档分类
最新评论

转 Spring动态注册bean实现动态多数据源

阅读更多

项目原来已经实现了多数据源配置,实现方式为在beans.xml文件中直接配置多个数据源bean,然后在使用数据源时通过HotSwappableTargetSource动态切换数据源(详细内容请Google)。可领导不满意,要求只在属性文件中配置相应的连接信息,并要求动态数据源除配置的属性外,其他属性都继承系统默认数据源(DataSource)的属性。然后给出的属性文件中数据源的格式为:

[plain]
#连接数据库地址,该地址可动态添加,“link.”之后,“.jdbc”之前的名称为数据库连接池的名称,其余连接池属性如果不写,将自动继承Hummer的数据库连接池配置
link.eagle2.business.jdbc.jdbcUrl=jdbc:oracle:thin:@192.168.0.155:1521:orcl
link.eagle2.business.jdbc.user=eagle2
link.eagle2.business.jdbc.password=eagle2_password
link.eagle2.interface.jdbc.jdbcUrl=jdbc:oracle:thin:@192.168.0.155:1521:interface
link.eagle2.interface.jdbc.user=interface
link.eagle2.interface.jdbc.password=interface22
link.eagle2.ods.jdbc.jdbcUrl=jdbc:oracle:thin:@192.168.0.10:1521:sifen
link.eagle2.ods.jdbc.user=honghe
link.eagle2.ods.jdbc.password=honghe_pwd

为实现这个要求,我经过google搜索,写代码尝试,最后终于较好的实现了该功能,结果记录如下:
实现一个实现ApplicationContextAware和ApplicationListener接口的类DynamicDataSourceC3p0,实现ApplicationContextAware是为了得到ApplicationContext,实现了ApplicationListener是为了配置spring的加载事件。
类的实现代码如下:
[java]
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.ChildBeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.io.support.ResourcePropertySource;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class DynamicDataSourceC3p0 implements ApplicationContextAware,ApplicationListener {

    private ApplicationContext app;
    @Override
    public void setApplicationContext(ApplicationContext app)
            throws BeansException {
        this.app = app;
    }
    public void onApplicationEvent(ApplicationEvent event) {  
        //如果是容器刷新事件  
        if(event instanceof ContextRefreshedEvent ){//如果是容器关闭事件  
            try {
                regDynamicBean();
            } catch (IOException e) {
                e.printStackTrace();
            }
            //System.out.println(event.getClass().getSimpleName()+" 事件已发生!");
        }
    }  

    private void regDynamicBean() throws IOException{
        // 解析属性文件,得到数据源Map
        Map<String, DataSourceInfo> mapCustom = parsePropertiesFile("hummer.properties");
        // 把数据源bean注册到容器中
        addSourceBeanToApp(mapCustom);
        
    }
    /**
     * 功能说明:根据DataSource创建bean并注册到容器中
     * @param acf
     * @param mapCustom
     */
    private void addSourceBeanToApp(Map<String, DataSourceInfo> mapCustom) {
        DefaultListableBeanFactory acf = (DefaultListableBeanFactory) app.getAutowireCapableBeanFactory();
        BeanDefinition beanDefinition;
        Iterator<String> iter = mapCustom.keySet().iterator();
        while(iter.hasNext()){
            String beanKey = iter.next();
            // 得到Bean定义,并添加到容器中
            beanDefinition = new ChildBeanDefinition("dataSource");
            // 注意:必须先注册到容器中,再得到Bean进行修改,否则数据源属性不能有效修改
            acf.registerBeanDefinition(beanKey, beanDefinition);
            // 再得到数据源Bean定义,并修改连接相关的属性
            ComboPooledDataSource cpds = (ComboPooledDataSource)app.getBean( beanKey);;

            cpds.setJdbcUrl(mapCustom.get(beanKey).connUrl);
            cpds.setUser(mapCustom.get(beanKey).userName);
            cpds.setPassword(mapCustom.get(beanKey).password);
        }
    }
    /**
     * 功能说明:解析属性文件,得到数据源Map
     * @return
     * @throws IOException
     */
    private Map<String, DataSourceInfo> parsePropertiesFile(String fileName) throws IOException {
        // 属性文件
        ResourcePropertySource props =  new ResourcePropertySource(fileName);
        
        Matcher matcher;
        Pattern pattern = Pattern.compile("^link\\.(eagle2\\.\\w+)\\.jdbc\\.(jdbcUrl|user|password)$");
        
        Map<String, DataSourceInfo> mapDataSource = new HashMap<String,DataSourceInfo>();
        // 根据配置文件解析数据源
        for(String keyProp : props.getPropertyNames())
        {
            matcher = pattern.matcher(keyProp);
            if(matcher.find()){
                String dsName = matcher.group(1);
                String dsPropName = matcher.group(2);
                DataSourceInfo dsi;
                
                if(mapDataSource.containsKey(dsName)){
                    dsi = mapDataSource.get(dsName);
                }
                else{
                    dsi = new DataSourceInfo();
                }
                // 根据属性名给数据源属性赋值
                if("jdbcUrl".equals(dsPropName)){
                    dsi.connUrl = (String)props.getProperty(keyProp);
                }else if("user".equals(dsPropName)){
                    dsi.userName = (String)props.getProperty(keyProp);
                }else if("password".equals(dsPropName)){
                    dsi.password = (String)props.getProperty(keyProp);
                }
                mapDataSource.put(dsName, dsi);
            }
        }
        return mapDataSource;
    }
    
    private class DataSourceInfo{
        public String connUrl;
        public String userName;
        public String password;
        
        public String toString(){
            
            return "(JcbcUrl:"+connUrl+", user:"+userName+", password:"+password+")";
        }
    }
}

然后在beans.xml文件中添加配置
"ApplicationEventListener" class="com.dfsoft.hummer.domain.common.DynamicDataSourceC3p0" />
让spring在加载时调用DynamicDataSourceC3p0中的onApplicationEvent方法实现动态注册数据源。而原来实现多数据源动态切换的地方完全不用修改。
附加说明:
1、 做完上面的工作之后,在beans.xml中去掉原来的多数据源配置(已经没有用了)。
2、 acf.registerBeanDefinition不用判断容器中是否已经有相应名字的bean,spring会在该名称的bean存在时覆盖,不存在时添加。
如侵权,请通知删除。http://www.2cto.com/kf/201210/160914.html
分享到:
评论

相关推荐

    spring 重新动态加载数据库或xml中的bean,可以不用重启tomcat

    spring 重新动态加载数据库或xml中的bean,可以不用重启tomcat

    Spring多数据源配置_分布式数据

    Spring多数据源配置_分布式数据 Tomcat服务器下的多数据源配置详情 一、环境及框架 Tomcat+spring+hibernate+jotm,还有就是struts、Oracle等 二、需求说明 系统里有2套不同网域的oracle数据库,之间的数据需要进行...

    spring多数据源 创建 切换使用

    项目中我们经常会遇到多数据源的问题,尤其是数据同步或定时任务等项目更是如此。多数据源让人最头痛的,不是配置多个数据源,而是如何能灵活动态的切换数据源。 spring多数据源 动态 创建 切换使用

    spring框架配置bean的高级属性

    可以利用hibernate tools生成相关映射文件已经po对象、dao对象,dao也可以自己手动编写,无非就是实现crud,如果通过继承hibernate提供的HibernateDaoSupport,则可以更轻松的实现 ...--配置数据源--&gt;

    Spring3中配置DBCP,C3P0,Proxool,Bonecp数据源

    在Spring3中配置数据源,包括DBCP,C3P0,Proxool,Bonecp主要的数据源,里面包含这些数据源的jar文件和依赖文件及配置文件。。 如Bonecp目前听说是最快的数据源,速度是传统的c3p0的25倍, bonecp.properties文件: ...

    spring Ioc容器配置

    IOC容器数据源配置 &lt;!-- 配置数据源 --&gt; &lt;bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"&gt; &lt;value&gt;org.gjt.mm.mysql.Driver &lt;value&gt;jdbc:mysql:/...

    Spring AOP 动态多数据源的实例详解

    Spring AOP 动态多数据源的实例详解 当项目中使用到读写分离的时候,我们就会遇到多数据源的问题。多数据源让人最头痛的,不是配置多个数据源,而是如何能灵活动态的切换数据源。例如在一个spring和Mybatis的框架的...

    Spring数据源配置

    Spring配置数据源的三种方式,非常详细!

    高级开发spring面试题和答案.pdf

    @transaction多个数据源事务怎么指定数据源 传播特性有几种?7种; 某一个事务嵌套另一个事务的时候怎么办? REQUIRED_NEW和REQUIRED区别 Spring的事务是如何回滚的,实现原理; 抽象类和接口的区别,什么时候用...

    Spring Boot 全局懒加载机制.docx

    但是现在 spring boot 应用中引入了很多第三方 starter ,比如 druid-spring-boot-starter 数据源注入、spring-boot- starter-data-redis 缓存等默认情况下, 引入即注入了相关 bean 我们无法去修改添加 @Lazy 。

    spring-boot-mybatis-multidatasource多数据源配置(oracle)

    3, application.yml中配置了双数据源,根据需要可以加多个数据源,同时要在datasource包中新建数据源配置,参考那两个配置。 4, 启动项目,测试接口在DataSourceController中,只用注入相关的bean就能使用。 5, 使用...

    spring源代码解析

    而一般的启动过程,Spring会使用一个默认的实现,XmlWebApplicationContext – 这个上下文实现作为在web容器中的根上下文容器被建立起来,具体的建立过程在下面我们会详细分析。 Java代码 public class ...

    SpringMybatis:springMybatis多数据源

    Spring / Mybatis多数据源 Spring中的Mybatis多数据源集成。 你好? 上周使用spring4 + mybatis3.3 + dbcp 我们将上传解决连接多个数据源部分内容的内容。 Spring版:4.2.0 mybatis版本:3.3.0 mybatis-spring...

    spring 容器.docx

    Bean是Spring管理的基本单位,在基于Spring的Java EE应用中,所有的组件都被当成Bean处理,包括数据源、Hibernate的SessionFactory、事务管理器等。在Spring中,Bean的是一个非常广义的概念,任何的Java对象、Java...

    spring+springmvc+mybatis的整合

    2.4 spring-db 我这里创建数据源,但是alt+/出不来提示,我一想,mysql的包没载入,在maven中加入 还是没得,恩,我加了jdbc的包,还是没有,我以为是没有源码,下载了,还是没有提示,棒 没有提示,我追了下源码...

    Spring-Reference_zh_CN(Spring中文参考手册)

    配置子报表数据源 14.7.5. 配置Exporter的参数 15. 集成其它Web框架 15.1. 简介 15.2. 通用配置 15.3. JavaServer Faces 15.3.1. DelegatingVariableResolver 15.3.2. FacesContextUtils 15.4. Struts 15.4.1. ...

    Spring 2.0 开发参考手册

    12.2.4. 不使用回调的基于Spring的DAO实现 12.2.5. 基于Hibernate3的原生API实现DAO 12.2.6. 编程式的事务划分 12.2.7. 声明式的事务划分 12.2.8. 事务管理策略 12.2.9. 容器资源 vs 本地资源 12.2.10. 在应用...

    Spring中文帮助文档

    12.2.4. 不使用回调的基于Spring的DAO实现 12.2.5. 基于Hibernate3的原生API实现DAO 12.2.6. 编程式的事务划分 12.2.7. 声明式的事务划分 12.2.8. 事务管理策略 12.2.9. 容器资源 vs 本地资源 12.2.10. 在应用...

    Spring API

    12.2.4. 不使用回调的基于Spring的DAO实现 12.2.5. 基于Hibernate3的原生API实现DAO 12.2.6. 编程式的事务划分 12.2.7. 声明式的事务划分 12.2.8. 事务管理策略 12.2.9. 容器资源 vs 本地资源 12.2.10. 在应用...

    Spring.3.x企业应用开发实战(完整版).part2

    8.4.3 Spring的数据源实现类 8.5 小结 第9章 Spring的事务管理 9.1 数据库事务基础知识 9.1.1 何为数据库事务 9.1.2 数据并发的问题 9.1.3 数据库锁机制 9.1.4 事务隔离级别 9.1.5 JDBC对事务支持 9.2 ThreadLocal...

Global site tag (gtag.js) - Google Analytics