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的。如果你動手嘗試以上的例子,會幫助你獲得更好的理解。