就是當知足特定的條件時Spring容器才建立Bean,Spring中經過@Conditional註解來實現條件化配置beanweb
package com.sl.ioc; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; @Configuration public class AnimalConfig { @Bean("dog") @Conditional(DogCondition.class) public Dog DogInstance() { return new Dog(); } @Bean("cat") @Conditional(CatCondition.class) public Cat CatInstance() { return new Cat(); } }
@Conditional和 :Condition接口的實現spring
public @interface Conditional { /** * All {@link Condition}s that must {@linkplain Condition#matches match} * in order for the component to be registered. */ Class<? extends Condition>[] value(); } public interface Condition { /** * Determine if the condition matches. * @param context the condition context * @param metadata metadata of the {@link org.springframework.core.type.AnnotationMetadata class} * or {@link org.springframework.core.type.MethodMetadata method} being checked * @return {@code true} if the condition matches and the component can be registered, * or {@code false} to veto the annotated component's registration */ boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata); }
Conditional註解經過value傳入一個類,實現Condition接口,經過實現Condition接口中matches方法決定是否須要裝配Bean,若是知足條件須要建立bean則返回true,不然返回false緩存
本身定義兩個繼承Condition接口的類:經過ConditionContext查找當前環境中是否存在dog或者cat屬性,若是存在,則建立對應的bean對象,具體實現以下:session
package com.sl.ioc; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotatedTypeMetadata; public class DogCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { Environment environment = context.getEnvironment(); boolean flag= environment.containsProperty("dog"); return flag; } }
package com.sl.ioc; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotatedTypeMetadata; public class CatCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { Environment environment = context.getEnvironment(); boolean flag= environment.containsProperty("cat"); return flag; } }
package com.sl.ioc; import org.springframework.stereotype.Component; @Component public interface Animal { void Say(); } package com.sl.ioc;import org.springframework.stereotype.Component; @Component public class Cat implements Animal { @Override public void Say() { System.out.println("I am a cat"); } } package com.sl.ioc; import org.springframework.stereotype.Component; @Component public class Dat implements Animal { @Override public void Say() { System.out.println("I am a dog"); } }
測試代碼:ide
public class TestClass { @Test public void TestGetDoInstance() { System.setProperty("dog",""); ApplicationContext context = new AnnotationConfigApplicationContext(AnimalConfig.class); String[] beanNames = context.getBeanDefinitionNames(); for(String bean : beanNames) { System.out.println(bean); } } }
運行測試能夠看到輸出的beanname中會包含dog的bean:函數
Spring自動裝配時若是存在多個bean可以匹配的話,那麼這種狀況會阻礙Spring經過屬性、構造函數或方法進行裝配。針對這種狀況,Spring提供了多種 可選方案來解決這個問題,能夠選擇一個bean做爲首選的bean,或者使用限定符來肯定惟一bean測試
Spring提供@Primary註解來設置首選Bean,當初選自動裝配歧義時,會選擇裝配帶有@Primary的beanspa
沿用上面的示例代碼,嘗試裝載animalprototype
@Component public class AnimalInstance { @Autowired public Animal animal; }
當Spring嘗試注入animal實例時,因爲Dog和Cat都繼承自Animal,因此此處產生了歧義,下面經過使用@Primary指定首選beancode
@Component @Primary //指定首選bean public class Cat implements Animal { @Override public void Say() { System.out.println("I am a cat"); } }
一樣也可使用XML配置來實現:<bean>元素提供了primary屬性來設置首選bean
<bean id="cat" class="com.sl.ioc.Cat" primary ="true" >
測試代碼:
public class TestClass { @Test public void TestGetDoInstance() { //應用上下文 ApplicationContext context = new AnnotationConfigApplicationContext(AnimalConfig.class); AnimalInstance animalInstance = context.getBean(AnimalInstance.class); animalInstance.animal.Say(); } }
運行結果:
首選項只是標識一個優先選擇裝載的bean,若是配置了多個@Primary,那麼將帶來新的歧義,Spring依然沒法完成自動裝配,能夠經過下面限定符來解決這個問題
Spring提供@Qualifier註解來指定想要注入的具體bean。例如上面的示例,若是指定注入dog:
package com.sl.ioc; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; @Component public class AnimalInstance { @Autowired @Qualifier("dog") public Animal animal; }
解釋一下:@Qualifier("dog")表示指定的bean具備」dog」限定符,spring中bean若是沒有指定限定符,會使用默認限定符,即便用beanID做爲限定符。因此上面是剛好使用了dog bean的ID做爲了限定符。也能夠寫成以下方式:
@Component @Qualifier("specialdog") //爲bean指定限定符 public class Dog implements Animal { @Override public void Say() { System.out.println("I am a dog"); } }
@Component public class AnimalInstance { @Autowired @Qualifier("specialdog") //使用上面定義的限定符 public Animal animal; }
Spring容器在建立bean實例的同時,還容許指定bean實例的做用域,常見做用域有一下幾種:
1:單例做用域(Singleton)
2:原型做用域(Prototype)
3:會話做用域(Session)
4:請求做用域(Request)
5:全局會話做用域(globalSession)
在整個應用中,Spring IOC容器爲使用singleton模式的bean只建立一個實例,Spring將會緩存Bean實例,任何對該類型beand請求都會返回該實例。單例也是Spring默認的做用域。具體使用以下,經過XML配置
<bean id="beanid" class="com.sl.ioc.xxx" scope="singleton" ></bean>
<bean>元素提供了scope屬性來設置singleton做用域
對應的註解:
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
每次注入或者從Spring容器中獲取時都建立一個新的bean實例:
<bean id="beanid" class="com.sl.ioc.xxx" scope="prototype" ></bean>
<bean>元素提供了scope屬性來設置singleton做用域
對應的註解:
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
在web應用中,針對每一個會話,Spring容器根據bean定義建立的bean實例,只在當前會話Session中有效,XML配置以下:
<bean id="beanid" class="com.sl.ioc.xxx" scope="session" ></bean>
針對某個HTTP Session,Spring容器會根據bean定義建立一個新的bean實例,該bean僅在當前HTTP Session內有效。因此能夠根據須要放心的更改bean實例的內部狀態,而不影響其餘Http Session中bean實例。當HTTP Session最終被廢棄的時候,在該HTTP Session做用域內的bean也會被銷燬掉。
<bean id="beanid" class="com.sl.ioc.xxx" scope="globalSession" ></bean>
在web應用中,針對每次請求,Spring容器根據bean定義建立新的bean實例,只在當前請求內有效
<bean id="beanid" class="com.sl.ioc.xxx" scope="request" ></bean>
該bean實例只在當前請求內有效,在請求處理完成以後bean也會被銷燬掉
相似於session做用域,只是其用於portlet環境的web應用。若是在非portlet環境將視爲session做用域。