简体   繁体   English

使用xml配置在spring boot中有条件地加载一个bean?

[英]Conditionally load a bean in spring boot using xml configuration?

I am using Spring Boot 2.1.我正在使用 Spring Boot 2.1。

I have some mixed configuration in my project : XML files and java classes with annotations.我的项目中有一些混合配置:XML 文件和带有注释的 Java 类。 We have this current configuration which works :我们有这个有效的当前配置:

application.properties :应用程序属性:

spring.profiles.active=dev, component1, component2

applicationContext-file.xml : applicationContext-file.xml :

 <?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:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd"
  profile="component1"> 
    <beans>
        <bean id="myserviceimpl"
            class="org.blabla.MyServiceImpl">
            <property name="mydao">
                <ref bean="mydao"></ref>
            </property>
        </bean>
    </beans>
</beans>   

We want to extract the component values from the spring.profiles.active property since they have nothing to do with the environment :我们想从 spring.profiles.active 属性中提取组件值,因为它们与环境无关:

application.properties :应用程序属性:

spring.profiles.active=dev
component1=true
component2=true

How can i condition the instantiation of the myserviceimpl bean inside the applicationContext-file.xml ?如何在 applicationContext-file.xml 中调节 myserviceimpl bean 的实例化? I can no longer rely on the profile attribute since the spring.profiles.active property no longer includes the values of the components.我不能再依赖 profile 属性,因为 spring.profiles.active 属性不再包含组件的值。

Thanks for helping.谢谢你的帮助。

I haven't tried it by myself but I suggest to check the following:我自己没有尝试过,但我建议检查以下内容:

Step 1第1步

Create one XML file per profile (say, dev and prod for the sake of example):为每个配置文件创建一个 XML 文件(例如, devprod ):

app-config-dev.xml:
------------------

<?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:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd"
  profile="dev"> 
    <beans>
       <!-- here define only beans that you want to load in __dev__ environment -->
        <bean id="myserviceimpl"
            class="org.blabla.MyServiceImpl">
            <property name="mydao">
                <ref bean="mydao"></ref>
            </property>
        </bean>
    </beans>
</beans> 
app-config-prod.xml:
------------------

<?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:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd"
  profile="prod"> 
    <beans>
        <!-- here define only beans that you want to load in __production__ environment -->
        <bean id="myserviceimpl"
            class="org.blabla.MyServiceProdImpl">
            <property name="mydao">
                <ref bean="mydao"></ref>
            </property>
        </bean>
    </beans>
</beans> 

Step 2第2步

Now in your "primary" applicationContext-file.xml instead of defining beans directly, include all the xml files that you've created during the step 1:现在在您的“主要”applicationContext-file.xml 中,而不是直接定义 bean,包括您在步骤 1 中创建的所有 xml 文件:

<import resource="classpath:app-config-dev.xml" /> 
<import resource="classpath:app-config-prod.xml" /> 
  • Read this thread for more details on this step if needed如果需要,请阅读此线程以获取有关此步骤的更多详细信息

Step 3第 3 步

Remove the component1=true and component2=true from aplication properties, you don't need it anymore, the profile itself defines which beans should be loaded.从应用程序属性中删除component1=truecomponent2=true ,您不再需要它了,配置文件本身定义了应该加载哪些 bean。

Update 1更新 1

Based OP's first comment:基于 OP 的第一条评论:

You probably can try another option but I consider it a "low-level" solution and it requires deep understanding of how does spring loading process work under the hood.您可能可以尝试另一种选择,但我认为它是“低级”解决方案,它需要深入了解弹簧加载过程如何在幕后工作。

So when spring starts it finds the definitions of beans (in xml, java config, annotations like @Component and so forth) and creates out of all this information a BeanDefinition - a metadata object that aggregates all the information about the bean (for example whether its singleton or prototype).因此,当 spring 启动时,它会找到 bean 的定义(在 xml、java 配置、 @Component等注释中)并根据所有这些信息创建一个BeanDefinition一个聚合关于 bean 的所有信息的元数据对象(例如它的单例或原型)。 At this point no beans are not created yet.此时还没有创建任何bean。 Lets call this point in time a "Bean Definitions Done" point" (for the sake of explanations, its my term out of my head...让我们称这个时间点为“完成 Bean 定义”点”(为了解释起见,这是我的术语……

Then spring starts to build a graph of dependencies and starts creating beans, initializing them (Autowiring, post-construct methods, and so on) and placing them onto application context (if they're singletons).然后 spring 开始构建依赖关系图并开始创建 bean,初始化它们(自动装配、后构造方法等)并将它们放置到应用程序上下文中(如果它们是单例)。

Now, in spring there is an option to provide a hook called BeanFactoryPostProcessor that is invoked exactly at the "Bean Definitions Done" point.现在,在 spring 中有一个选项可以提供一个名为BeanFactoryPostProcessor的钩子,该钩子恰好在“Bean Definitions Done”点调用。 This is basically a java code that implements some interface and by itself is a spring bean that spring treats in a special way.这基本上是一个实现一些接口的java代码,它本身就是一个spring以特殊方式处理的spring bean。

So you can implement this interface and manipulate the results of Bean factory.所以你可以实现这个接口并操作Bean工厂的结果。 Namely you can access every bean definition that spring has opened and if you think that the bean of this definition should not be created (here comes your custom logic that would check properties, whatever) - remove the bean definition from the registry: For technical method of removing bean definitions see this thread也就是说,您可以访问 spring 已打开的每个 bean 定义,并且如果您认为不应创建此定义的 bean(这里是您的自定义逻辑来检查属性,无论如何) - 从注册表中删除 bean 定义:对于技术方法删除 bean 定义请参阅此线程

Here is an example of Bean Factory Post processor that actually adds a new bean although it wasn't registered 是一个 Bean Factory Post 处理器的例子,它实际上添加了一个新的 bean,虽然它没有注册

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM