【譯】Spring 4.0帶來的@Conditional註解

沈子平發表於2017-09-06

Spring 4.0帶來的@Conditional註解

本文會接觸spring 4的新功能:@Conditional註解。在之前的spring版本中,你處理conditions只有以下兩個方法:

  • 在3.1版本之前,你需要使用spring expression language
  • 在3.1版本釋出時,profiles被引入來處理conditions。

讓我們分別看看以上兩者,在來理解spring 4帶來的@Conditional註解。

Spring Expression Language(SPeL)

SPeL的三元識別符號(IF-THEN-ELSE)可以在spring配置檔案中用來表達條件語句。

<bean id="flag">
   <constructor-arg value="#{systemProperties[`system.propery.flag`] ?: false }" />
</bean>
<bean id="bean">
    <property name="property" value="#{ flag ? `yes` : `no` }"/>
</bean>

這個bean的屬性依賴於flag的值,該值是使用外部屬性注入的,這樣bean就具有了動態的能力。

使用 Profiles

這是在spring 3.1引入的。像下面這樣使用。

<!-- default configuration - will be loaded if no profile is specified -->
<!-- This will only work if it`s put at the end of the configuration file -->
<!-- so no bean definitions after that -->
<beans profile="default">
     <import resource="classpath:default.xml" />
</beans>
<!-- some other profile -->
<beans profile="otherProfile">
    <import resource="classpath:other-profile.xml" />
</beans>

使用spring 4的@Conditional註解

現在介紹@Conditional註解。官方文件的說明是“只有當所有指定的條件都滿足是,元件才可以註冊”。主要的用處是在建立bean時增加一系列限制條件。

Conditional介面的宣告如下:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE, ElementType.METHOD)
public @interface Conditional{
    Class <!--?extends Condition-->[] value();
}

所以@Conditional註解使用方法如下

  • 型別級別,可以在@Component 或是 @Configuration類上使用
  • 原型級別,可以用在其他自定義的註解上
  • 方法級別,可以用在@Bean的方法上

如果一個@Configuration類使用了@Conditional,會影響所有@Bean方法和@Import關聯類

public interface Condition{
/** Determine if the condition matches.
* @param context the condition context
* @param metadata meta-data of the {@link AnnotationMetadata class} or
* {@link Method method} being checked.
* @return {@code true} if the condition matches and the component can be registered
* or {@code false} to veto registration.
*/
boolean matches(ConditionContext context, AnnotatedTypeMedata metadata);
}

下面是一個例子

public class SystemPropertyCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata         metadata) {
        return (System.getProperty("flag") != null);
    }
}

class SystemPropertyAbsentCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return (System.getProperty("flag") == null);
    }
}

這裡我們有兩個類:SystemPropertyCondition和SystemPropertyAbsentCondtion. 這兩個類都實現了Condition介面.覆蓋的方法基於屬性flag返回一個布林值。
現在我們定義兩個類,一個是positive條件,一個是negative條件:

@Bean
@Conditional(SystemPropertyCondition.class)
public SampleService service1() {
    return new SampleServiceImpl1();
}

@Bean
@Conditional(SystemPropertyAbsentCondition.class)
public SampleService service2() {
    return new SampleServiceImpl2();
}

上面提到的profiles已經通過conditional原型註解進行了修改。

總結

本文介紹了spring 4的conditianal註解。注意condition註解是不會繼承的。如果一個父類使用了conditional註解,其子類是不會擁有conditions的。如果你動手嘗試以上的例子,會幫助你獲得更好的理解。

相關文章