`
LynsaHuang
  • 浏览: 47034 次
  • 性别: 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
分享到:
评论

相关推荐

    SpringBoot配置多数据源实现动态切换数据源

    本文将深入探讨如何在SpringBoot项目中配置多数据源,并实现数据源的动态切换,帮助你理解和掌握这一核心技能。 首先,我们理解"多数据源"的概念。在SpringBoot应用中,多数据源意味着系统能够连接并操作多个不同的...

    mybatis+spring实现动态切换数据源

    在本项目中,我们将探讨如何利用MyBatis与Spring框架实现动态切换数据源的功能。首先,我们需要理解MyBatis和Spring的基本概念以及它们如何协同工作。 MyBatis是一个优秀的持久层框架,它简化了Java与数据库之间的...

    通过Spring Boot配置动态数据源访问多个数据库的实现代码

    Spring Boot配置动态数据源访问多个数据库实现代码详解 通过Spring Boot配置动态数据源访问多个数据库可以实现数据库的动态增删和数量无限的支持,下面将详细介绍该实现代码的知识点。 数据源配置管理 在Spring ...

    Spring之动态注册bean的实现方法

    例如,在一个支持扫表的基础平台中,我们需要根据用户的需求动态添加或删除 DataSource 数据源 Bean,以便满足不同的业务需求。 动态注册 Bean 的实现方法 在 Spring 中,我们可以使用 BeanDefinition 来实现动态...

    springboot-AOP实现多数据源动态切换(Druid连接池)

    在Spring Boot项目中实现多数据源动态切换是一项高级特性,能够使应用根据不同业务需求访问不同的数据库,从而实现服务的解耦和数据库操作的优化。该技术的关键在于如何在同一个应用中配置和使用多个数据源,以及...

    Spring+SpringMVC+Mybatis动态链接多数据源

    在企业级应用开发中,数据源管理是至关重要的部分,特别...通过这个项目,你可以学习到如何在Spring、SpringMVC和Mybatis的环境下实现动态多数据源的配置和管理,这对于大型分布式系统的设计和开发具有很高的实践价值。

    spring 动态切换数据源

    在Spring框架中,动态切换数据源是一项重要的功能,它允许应用程序根据业务需求在多个数据库之间灵活切换。这一特性对于多租户系统、读写分离、分布式数据库等场景尤其有用。以下将详细介绍如何实现Spring的动态数据...

    spring boot AOP注解方式实现多数据源

    在Spring Boot中,AOP(面向切面编程)和多数据源的整合是常见的应用场景,尤其是在大型企业级项目中,为了实现数据的隔离或者优化数据库访问,常常需要配置多个数据源。本文将深入探讨如何使用Spring Boot的AOP注解...

    真正意义的spring动态切换数据源源码

    总结,Spring动态切换数据源是企业级应用中不可或缺的功能,它通过灵活的策略和强大的容器管理能力,实现了在运行时无缝地在多个数据源之间切换,从而满足了复杂的应用场景需求。通过深入理解和掌握这一技术,我们...

    spring动态选择数据源

    Spring动态数据源的实现主要依赖于Spring的AOP(面向切面编程)和Bean工厂。通过AOP,我们可以在方法执行前后插入特定的逻辑,比如在执行SQL之前选择正确的数据源。在Spring中,我们通常会创建一个`...

    springboot 1.5.9+mybatis动态指定数据源

    本文将深入探讨如何在Spring Boot 1.5.9版本中结合MyBatis实现动态指定数据源,并通过自定义注解来实现这一功能。 首先,我们需要理解动态数据源的概念。动态数据源是指在运行时可以动态切换或选择的数据源,这在多...

    Spring动态切换datasource实现mysql多住多从

    3. **定义数据源路由**:Spring的`AbstractRoutingDataSource`类可以帮助我们实现数据源的动态路由。我们需要创建一个继承自`AbstractRoutingDataSource`的类,并重写`determineCurrentLookupKey`方法,该方法将根据...

    spring boot多数据源(AOP注解动态切换)

    通过以上步骤,我们成功地在Spring Boot中实现了基于AOP注解的多数据源动态切换。这使得在运行时可以根据业务需求选择合适的数据源,提高了代码的灵活性和可维护性。在实际项目中,你可能还需要考虑事务管理、数据源...

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

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

    spring多数据源

    3. **配置多数据源**:在Spring的XML配置文件中,我们需要定义多个DataSource bean,分别代表不同的数据库连接。这些数据源可以是Apache Commons DBCP、HikariCP、Druid等连接池的实现。例如: ```xml &lt;bean id=...

    SpringBoot整合mybatis-plus实现多数据源的动态切换且支持分页查询.pdf

    在SpringBoot项目中,整合Mybatis-Plus并实现多数据...以上就是SpringBoot整合Mybatis-Plus实现多数据源动态切换并支持分页查询的详细过程。这个实现方案能够有效地应对复杂的数据库环境,提高系统的灵活性和可扩展性。

    spring boot多数据源配置

    通过以上步骤,我们就完成了Spring Boot的多数据源配置,实现了从数据源配置、实体管理、Mapper到Controller的完整业务流程。在实际开发中,可以根据具体需求进行调整,例如增加事务管理、数据源切换策略等。

    Springboot 动态多数据源 jta分布式事务

    本资源针对的是Spring Boot动态多数据源和JTA(Java Transaction API)分布式事务的实现,对于初学者来说非常实用。下面我们将深入探讨这些知识点。 首先,让我们了解一下Spring Boot的多数据源。在许多业务场景下...

    spring boot 2多数据源,里面有hibernate和mybatis的多数据源代码

    在Spring Boot 2框架中,实现多数据源的配置是一项重要的任务,特别是在大型企业级应用中,可能需要连接到不同的数据库来满足不同业务的需求。在这个项目中,我们有两个主要的数据访问技术:Hibernate和MyBatis,...

    使用springboot + JPA / MyBatis 实现多数据源动态切换

    在现代企业级应用开发...总的来说,Spring Boot结合JPA或MyBatis实现多数据源动态切换,不仅提高了系统的灵活性,还便于进行数据库扩展和管理。理解和掌握这一技术,对于提升系统设计能力和解决复杂问题具有重要意义。

Global site tag (gtag.js) - Google Analytics