Java 我们可以有条件地声明spring bean吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/39857804/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 21:30:14  来源:igfitidea点击:

Can we declare spring bean conditionally?

javaspring

提问by Dimitrios Efthymiou

Is there a way we can declare a Spring bean conditionally like:

有没有一种方法可以有条件地声明一个 Spring bean,例如:

<bean class="path.to.the.class.MyClass" if="${1+2=3}" />

It would be useful instead of having to use profiles. I don't have a specific use-case in mind, but it came to me.

这将很有用,而不必使用配置文件。我没有想到特定的用例,但我想到了。

回答by Sundararaj Govindasamy

You can use @Conditionalfrom Spring4or @ConditionalOnPropertyfrom Spring Boot.

您可以使用@Conditional从春季4@ConditionalOnProperty从春天启动

  1. Using Spring4 (only)
  1. 使用 Spring4(

if you are NOTusing Spring Boot, this can be overkill.

如果您使用 Spring Boot,这可能有点矫枉过正

First, create a Conditionclass, in which the ConditionContexthas access to the Environment:

首先,创建一个Condition类,在其中ConditionContext可以访问Environment

public class MyCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context,
                           AnnotatedTypeMetadata metadata) {
        Environment env = context.getEnvironment();
        return null != env
                && "true".equals(env.getProperty("server.host"));
    }
}

Then annotate your bean:

然后注释你的bean:

@Bean
@Conditional(MyCondition.class)
public ObservationWebSocketClient observationWebSocketClient() {
    //return bean
}

2.Using Spring Boot:

2.使用Spring Boot

@ConditionalOnProperty(name="server.host", havingValue="localhost")

And in your abcd.propertiesfile ,

在你的abcd.properties文件中,

server.host=localhost

回答by Koos Gadellaa

I have a snippet for such a thing. It checks the value of a property which is set in the annotation, so you can use things like

我有这样一个片段。它检查在注释中设置的属性的值,因此您可以使用诸如

@ConditionalOnProperty(value="usenew", on=false, propertiesBeanName="myprops")
@Service("service")
public class oldService implements ServiceFunction{
    // some old implementation of the service function.
}

It even allows you to define different beans with the same name:

它甚至允许您定义具有相同名称的不同 bean:

@ConditionalOnProperty(value="usenew", on=true, propertiesBeanName="myprops")
@Service("service")
public class newService implements ServiceFunction{
    // some new implementation of the service function.
}

These two can be declared at the same time, allowing you to have a "service"named bean with differing implementations depending on whether the property is on or off...

这两个可以同时声明,允许您"service"根据属性是打开还是关闭来拥有一个具有不同实现的命名bean...

The snippet for it itself:

它本身的片段:

/**
 * Components annotated with ConditionalOnProperty will be registered in the spring context depending on the value of a
 * property defined in the propertiesBeanName properties Bean.
 */

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Conditional(OnPropertyCondition.class)
public @interface ConditionalOnProperty {
    /**
     * The name of the property. If not found, it will evaluate to false.
     */
    String value();
    /**
     * if the properties value should be true (default) or false
     */
    boolean on() default true;
    /**
     * Name of the bean containing the properties.
     */
    String propertiesBeanName();
}

/**
 * Condition that matches on the value of a property.
 *
 * @see ConditionalOnProperty
 */
class OnPropertyCondition implements ConfigurationCondition {
    private static final Logger LOG = LoggerFactory.getLogger(OnPropertyCondition.class);

    @Override
    public boolean matches(final ConditionContext context, final AnnotatedTypeMetadata metadata) {
        final Map attributes = metadata.getAnnotationAttributes(ConditionalOnProperty.class.getName());
        final String propertyName = (String) attributes.get("value");
        final String propertiesBeanName = (String) attributes.get("propertiesBeanName");
        final boolean propertyDesiredValue = (boolean) attributes.get("on");

        // for some reason, we cannot use the environment here, hence we get the actual properties bean instead.
        Properties props = context.getBeanFactory().getBean(propertiesBeanName, Properties.class);
        final boolean propValue = parseBoolean(props.getProperty(propertyName, Boolean.toString(false)));
        LOG.info("Property '{}' resolved to {}, desired: {}", new Object[] { propertyName, propValue, "" + propertyDesiredValue });
        return propValue == propertyDesiredValue;
    }
    /**
     * Set the registration to REGISTER, else it is handled during  the parsing of the configuration file
     * and we have no guarantee that the properties bean is loaded/exposed yet
     */
    @Override
    public ConfigurationPhase getConfigurationPhase() {
        return ConfigurationPhase.REGISTER_BEAN;
    }
}