【问题标题】:Dynamically load a spring xml file based on database values根据数据库值动态加载spring xml文件
【发布时间】:2013-05-12 15:21:58
【问题描述】:

我们目前有一个 Spring Web 应用程序,并且正在使用 XML 文件进行配置。我们正在启动 Spring DispatcherServlet,它创建一个 XmlWebApplicationContext 并从默认位置加载它:spring-servlet.xml。

我正在使用上下文参数 contextConfigLocation 指定几个额外的配置文件。这会从 XML 文件加载我们的整个应用程序。

这就是我想要做的。 XML 文件包含数据库连接信息和我们用于访问这些表的 DAO。我想使用其中一个 DAO 从数据库中读取一个值并从 XML 文件加载一组额外的 bean。

所以如果检索到的数据库值是橙色的,我想从 orange.xml 加载 bean。如果是苹果,我想加载apple.xml。我希望这些 bean 成为同一个应用程序上下文的一部分,因此在加载它们之后,我可以继续前进而不会注意到差异。

我想知道是否应该实现我自己的 XmlWebApplicationContext 子类并让 DispatcherServlet 实现它,但我不太确定如何继续。

【问题讨论】:

  • 可能是重复的。这有帮助吗:stackoverflow.com/questions/3035630/…
  • 我不这么认为。问题是我需要加载部分 bean,然后使用其中一个 bean,从动态指定的新 XML 文件中加载其余 bean。

标签: java spring jakarta-ee


【解决方案1】:

不完全从不同的文件加载,但您可以尝试使用 Spring Environment 和 Profile 抽象。

<beans profile="apple">
    <bean id="someBean">
       ...first set of bean parameters...
    </bean>
</beans>
<beans profile="orange">
    <bean id="someBean">
       ...second set of bean parameters...
    </bean>
</beans>

在java中:

context.getEnvironment().setActiveProfiles("orange");
context.refresh();

【讨论】:

  • 如果你能在 refresh() 之前解析出 orange 是好的配置文件,那么你可以直接添加 orange.xml 配置位置,并且根本不需要配置文件。
【解决方案2】:

您可以使用BeanFactoryPostProcessor 来加载配置。

例如,如果您有一个 LocationService 将配置位置作为 String[]:

public class XmlBeanDefinitionReaderPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader((BeanDefinitionRegistry) beanFactory);
        ResourceLoader resourceLoader = new DefaultResourceLoader();
        reader.setResourceLoader(new DefaultResourceLoader());
        reader.setEntityResolver(new ResourceEntityResolver(resourceLoader));
        reader.setEnvironment(new StandardEnvironment());
        LocationService locationService = (LocationService) beanFactory.getBean("locationService");

        reader.loadBeanDefinitions(locationService.getLocations());     
    }

}

不完全一样,因为读者不知道已经加载的 bean 并且可能是别名或 bean 名称 colisions。

请注意,您的LocationService 不应使用AutorwireAOP Transactional Proxies,以及通常暗示使用BeanPostProcessors 的内容。

重用相同XmlBeanDefinitionReader 的其他选项是覆盖XmlWebApplicationContext 中的postProcessBeanFactory 方法:

public class CustomWebApplicationContext extends XmlWebApplicationContext  {

    private XmlBeanDefinitionReader reader;

    @Override
    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
        this.reader = reader;
        super.loadBeanDefinitions(reader);
    }

    @Override
    protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        LocationService locationService = (LocationService) beanFactory.getBean("locationService");
        this.reader.loadBeanDefinitions(locationService.getLocations());

        super.postProcessBeanFactory(beanFactory);
    }

}

【讨论】:

    【解决方案3】:

    我们最终扩展了 XmlWebApplicationContext 并覆盖了 loadBeans 方法。我们加载 bean,查找提供我们配置的 bean,然后切换配置文件并使用新配置文件再次运行。

    感谢大家的帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-09-17
      • 1970-01-01
      • 1970-01-01
      • 2016-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-07
      相关资源
      最近更新 更多