今天被问到一个有意思的问题,就是通过固定的数据源A,动态产生数据源B。其实就是在properties文件中配置数据源A,然后把数据源B用占位。把数据源A查询到的数据动态的替换给数据源B的占位符。知道Spring IOC初始化的小伙伴都知道。替换占位符操作是的操作是在Spring 对象实例化之前进行的。所以常规方法就不能进行这样的操作,就只能应用Spring的父子容器。具体可以看org.springframework.beans.factory.HierarchicalBeanFactory这个类。
public interface HierarchicalBeanFactory extends BeanFactory {
/**
* 返回当前容器的父容器,如果没有就返回null
*/
BeanFactory getParentBeanFactory();
/**
* 返回当前BeanFactory是否包含名name的bean
*/
boolean containsLocalBean(String name);
}
典型的应用就是Spring Web MVC:
父容器不能使用子容器的bean.而子容器能够使用父容器的bean.
下面我们就是使用这个特性来达到之前的需求。
1、父容器 – parent.xml
定义父容器,提供动态数据库的查询datasource Bean.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:content="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<content:property-placeholder location="jdbc.properties" />
<bean id="dataSource1" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${dataSource1.driverClassName}"/>
<property name="url" value="${dataSource1.url}" />
</bean>
</beans>
2、父容器资源文件 – jdbc.properties
dataSource1.driverClassName=org.h2.Driver
dataSource1.url=localhost:h2
3、子容器 – datasource.xml
子容器,使用父容器的dataSource1 这个bean来查询dataSource2这个动态数据源。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:content="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean class="com.weimob.carl.user.spring.DataSourcePropertyPlaceholderConfigurer" >
<property name="dataSource" ref="dataSource1" />
</bean>
<bean id="dataSource2" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${dataSource2.driverClassName}" />
<property name="url" value="${dataSource2.url}" />
</bean>
</beans>
4、占位符替换类
重写org.springframework.core.io.support.PropertiesLoaderSupport的loadProperties方法来自定义占位符替换。
/**
* Created by Carl on 2016/9/24.
*/
public class DataSourcePropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
protected void loadProperties(Properties props) throws IOException {
// 只要能够注入成功就可以使用dataSource查找数据库
System.out.println("获取动态数据源的dataSource :" + dataSource);
props.put("dataSource2.driverClassName", "org.h2.Driver");
props.put("dataSource2.url", "haha");
}
}
5、Test类
public class Main {
public static void main(String[] args) {
ApplicationContext parent = new ClassPathXmlApplicationContext("parent.xml");
ApplicationContext dataSourceContext = new ClassPathXmlApplicationContext(new String[]{"datasource.xml"}, parent);
DataSource dataSource = (DataSource) dataSourceContext.getBean("dataSource2");
System.out.println("动态数据源 : " + dataSource);
}
}
6、运行结果
可以看到实现了动态替换数据源。