javascript
Spring之高级装配(二)
上一節(jié)提到Spring之裝配bean(一),我們已經(jīng)了解到了裝配的基礎知識,這部分是更為高級的bean裝配技術(shù)。
高級裝配內(nèi)容:
- spring profile
- 有條件的bean
- 處理自動裝配的歧義性
- bean的作用域
1.spring profile
應用程序從一個環(huán)境遷移到另一個環(huán)境。開發(fā)階段,某些環(huán)境相關(guān)做法可能并不適合遷移到生產(chǎn)環(huán)境中,甚至幾遍遷移過去也無法正常工作,所以在不同的環(huán)境中使用的bean可能不同。下面以datasource為例:
在Java配置類中配置(“dev”和“prod”生產(chǎn)環(huán)境):
@Configuration public class DataSourceConfig{@Bean(destroyMethod="shutdown")@Profile("dev")public DataSource dataSource(){return new EmbeddedDatabaseBuilder().addScript("classpath:schema.sqsl").addScript("classpath:test-data.sql").build();}@Bean@Profile("prod")public DataSource dataSource(){JndiObjectFactoryBean jndi=new JndiObjectFactoryBean();jndi.setJndiName("jdbc/myDS");jndi.setResourceRef(true);jndi.setProxyInterface(javax.sql.DataSource.class);return (DataSource) jndi.getObject();} }在xml中配置:
<beans xmlns="......."><beans profile="dev"><jdbc:embedded-database id="dataSource"><jdbc:script location="classpath:schema.sql" /><jdbc:script location="classpath:test-data.sql" /></jdbc:embedded-database></beans><beans profile="qa"><bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destory-method="close"p:url="jdbc:h2:tcp://dbserver/~/test".......p:maxActive="30"/></beans> </beans>激活(使用)哪一個profile:
<!--為應用山下文設置默認的profile--> <context-param><param-name>spring.profiles.default</param-name><param-name>dev</param-name> </context-param> <!--為Servlet設置默認的profile--> <servlet><servlet-name>appServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>spring.profiles.default</param-name><param-value>dev</param-value></init-param><load-on-startup>1</load-on-startup> </servlet>2.有條件的bean
假設你希望一個或多個bean只有在應用的類路徑下包含特定的庫時才創(chuàng)建。或者我們希望某個bean只有當另外某個特定的bean也聲明了之后才會創(chuàng)建。我們還可能要求只有某個特定的環(huán)境變量設置之后才會創(chuàng)建某個bean。在Spring4之前,很難實現(xiàn)這種級別的條件化配置,但是Spring4引入了一個新的@Conditioinal注解,他可以用到帶有@Bean注解的方法上。如果給定的條件計算結(jié)果為true,就會創(chuàng)建這個bean,否則的話,這個bean就會被忽略。
有條件的bean一般在java配置注入bean的方法中使用到。
如你所見,設置給@Conditional的類可以是任意實現(xiàn)了Condition接口的的類型。而實現(xiàn)這個接口只需要實現(xiàn)matches方法,如果matches方法返回true就創(chuàng)建該bean,如果返回false則不創(chuàng)建bean,上例中我們就是根據(jù)環(huán)境變量中是否存在magic變量,來決定matches的返回值,進而決定是否創(chuàng)建MagicBean的。
但是在實際生產(chǎn)中,ConditionContext context, AnnotatedTypeMetadata metadata這兩個參數(shù)可以對類中的其他信息進行判斷,有興趣可以查一下這兩個類的api。
3.處理自動裝配的歧義性
如果不僅有一個bean能夠匹配結(jié)果的話,這種歧義性阻礙Spring自動裝配屬性、構(gòu)造器參數(shù)或方法參數(shù)。 下面是一個例子:
@Autowired public void setDessert(Dessert dessert){this.dessert = dessert; } @Component public class Cake implements Dessert{...} @Component public class Cookies implements Dessert{...} @Component public class IceCream implements Dessert{...}在這里,當Spring試圖自動裝配setDessert()中的Dessert參數(shù)時,它并沒有唯一、無歧義的可選值。因而,Spring會拋出NoUniqueBeanDefinitionException;
解決方案1:將其中一個bean設置為首選
@Component @Primary public class Cake implements Dessert{...}或者在xml中
<bean id = "iceCream" class = "com.desserteater.Icecream" primary = "true"> </bean>解決方法2:使用限定符(qualifier)來幫助Spring將可選的bean的范圍縮小
@Autowired @Qualifier("cake") public void setDessert(Dessert dessert){this.dessert = dessert; }4、bean的作用域
- 單例(singleton):在整個應用中,只創(chuàng)建bean的一個實例。
- 原型(prototype):每次注入或者通過Spring應用上下文獲取的時候,都會創(chuàng)建一個新的bean實例。
- 會話(Session):在Web應用中,為每個會話創(chuàng)建一個bean實例。
- 請求(Request):在Web應用中,為每個請求創(chuàng)建一個bean實例。
單例是默認的作用域,但是正如之前所述,對于易變的類型,這并不合適。如果選擇其他的作用域,要使用@Scope注解,他可以與@Component(自動裝配)或@Bean(JavaConfig)一起使用。
例如,如果你使用組件掃描來發(fā)現(xiàn)聲明bean,那么你可以在bean的類上使用@Scope注解,將其聲明為原型bean,如下:
@Component @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) //@Scope("prototype") public class Notepad{...}或者
<bean id="notepad"class="com.myapp.Notepad"scope="prototype" />使用會話和請求作用域
@Component @Scope(value=WebApplicationContext.SCOPE_SESSION,proxyMode=ScopedProxyMode.INTERFACES) public ShoppingCart cart(){...}這里,我們將value設置成了WebApplicationContext中的SCOPE_SESSION常量(它的值是session)。這會告訴Spring為Web應用中的每個會話創(chuàng)建一個ShoppingCart。這會創(chuàng)建多個ShoppingCart bean 實例,但是對于給定的會話只會創(chuàng)建一個實例,在當前會話相關(guān)的操作中,這個bean實際上相當于單例。
@Scope同時還有一個proxyMode屬性,它被設置成了ScopedProxyMode.INTERFACES。這個屬性解決了將會話或請求作用域的bean注入到單例bean中所遇到的問題。作用域代理能夠延遲注入請求和會話作用域的bean。
在xml中注入:
<bean id="cart"class="com.myapp.ShoppingCart"scope="session"><aop:scoped-proxy /> </bean>總結(jié)
以上是生活随笔為你收集整理的Spring之高级装配(二)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring之装配Bean(一)
- 下一篇: gradle idea java ssm