摘要:注解只可以裝配只有一個(gè)實(shí)現(xiàn)類的例如下面的有三個(gè)實(shí)現(xiàn)類,自動(dòng)裝配時(shí),就會(huì)不知道選哪一個(gè),因而會(huì)報(bào)錯(cuò)誤。使用表達(dá)式語言進(jìn)行裝配使用的來引用待補(bǔ)充實(shí)例調(diào)用方法和訪問對(duì)象的屬性對(duì)峙進(jìn)行算數(shù),關(guān)系和邏輯運(yùn)算正則表達(dá)式匹配集合操作
完整代碼請(qǐng)見:https://github.com/codercuixi...
第一部分 @Profile注解的使用環(huán)境與profile 是否啟用某個(gè)bean,常用于數(shù)據(jù)庫bean
通過profile啟用不同的bean,特別是對(duì)于各種不同的數(shù)據(jù)庫(開發(fā)線,測(cè)試線,正式線),尤其管用。
1.1第一步 配置profile bean。通過@Profile修飾類或者方法名,來表明這個(gè)Bean是可以動(dòng)態(tài)啟動(dòng)與否的
package com.myapp; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; import org.springframework.jndi.JndiObjectFactoryBean; import javax.sql.DataSource; @Configuration public class DataSourceConfig { @Bean(destroyMethod = "shutdown") @Profile("dev") public DataSource embeddedDataSource() { return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.H2) .addScript("classpath:schema.sql") .addScript("classpath:test-data.sql") .build(); } @Bean @Profile("prod") public DataSource jndiDataSource() { JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean(); jndiObjectFactoryBean.setJndiName("jdbc/myDS"); jndiObjectFactoryBean.setResourceRef(true); jndiObjectFactoryBean.setProxyInterface(javax.sql.DataSource.class); return (DataSource) jndiObjectFactoryBean.getObject(); } }
1.2.第二步,激活profile。
通過@ActiveProfile來激活指定的Profile,啟用指定的數(shù)據(jù)庫Bean。
package profiles; import static org.junit.Assert.*; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import javax.sql.DataSource; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.myapp.DataSourceConfig; public class DataSourceConfigTest { @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes=DataSourceConfig.class) @ActiveProfiles("dev") public static class DevDataSourceTest { @Autowired private DataSource dataSource; @Test public void shouldBeEmbeddedDatasource() { assertNotNull(dataSource); JdbcTemplate jdbc = new JdbcTemplate(dataSource); Listresults = jdbc.query("select id, name from Things", new RowMapper () { @Override public String mapRow(ResultSet rs, int rowNum) throws SQLException { return rs.getLong("id") + ":" + rs.getString("name"); } }); assertEquals(1, results.size()); assertEquals("1:A", results.get(0)); } } @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes=DataSourceConfig.class) @ActiveProfiles("prod") public static class ProductionDataSourceTest { @Autowired private DataSource dataSource; @Test public void shouldBeEmbeddedDatasource() { // should be null, because there isn"t a datasource configured in JNDI assertNull(dataSource); } } }
1.3.通過兩個(gè)參數(shù)激活profile
spring.profiles.active和spring.profiles.default,優(yōu)先使用前者的配置。
設(shè)置這兩個(gè)參數(shù)的方式有如下幾種:(待補(bǔ)充完整)
作為DIspatcherServlet的初始化參數(shù)
作為Web應(yīng)用的上下文參數(shù)
作為JNDI條目
作為環(huán)境變量
作為JVM的系統(tǒng)屬性
在集成測(cè)試類上,使用@ActiveProfile注解設(shè)置。(也就是上面第二步演示的)
第二部分 條件化的bean通過@Conditional, 可以用到Bean上,當(dāng)條件為true,則創(chuàng)建該Bean;否則則不創(chuàng)建。
主要分為一下三步
1.像往常一樣定義Bean的POJO類
2.編寫org.springframework.context.annotation.Condition接口的類MagicExistsCondition,用來創(chuàng)建是否創(chuàng)建該Bean
3.將@Conditional(MagicExistsCondition.class)應(yīng)用到Bean的JavaConfig上。
package conditional.habuma.restfun; public class MagicBean { }
package conditional.habuma.restfun; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotatedTypeMetadata; /** * * @Author: cuixin * * @Date: 2018/8/30 18:32 */ public class MagicExistsCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { Environment environment = context.getEnvironment(); return environment.containsProperty("magic"); } }
package conditional.habuma.restfun; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; /** * * @Author: cuixin * * @Date: 2018/8/30 18:32 */ @Configuration public class MagicConfig { @Bean @Conditional(MagicExistsCondition.class) public MagicBean magicBean(){ return new MagicBean(); } }
由于實(shí)現(xiàn)了match方法中帶有兩個(gè)參數(shù),我們可以通過這兩個(gè)參數(shù)做到什么呢?
ConditionContext接口的方法
public interface ConditionContext { /** * 返回BeanDefinitionRegistry,可用來判斷Bean是否定義 */ BeanDefinitionRegistry getRegistry(); /** * 返回ConfigurableListableBeanFactory,可用來檢查Bean是否存在,甚至探查Bean的屬性 */ @Nullable ConfigurableListableBeanFactory getBeanFactory(); /** * 返回Environment,可用來判斷環(huán)境變量是否存在,且獲取環(huán)境變量的值 */ Environment getEnvironment(); /** *返回ResourceLoader,可用來讀取或探查已經(jīng)加載的資源 */ ResourceLoader getResourceLoader(); /** * 返回ClassLoader,可用來加載類或判斷類是否存在 */ @Nullable ClassLoader getClassLoader(); }
AnnotatedTypeMetadata 用來獲取注解相關(guān)信息
public interface AnnotatedTypeMetadata { boolean isAnnotated(String annotationName); @Nullable Map第三部分 處理自動(dòng)裝配的歧義性。getAnnotationAttributes(String annotationName); @Nullable Map getAnnotationAttributes(String annotationName, boolean classValuesAsString); @Nullable MultiValueMap getAllAnnotationAttributes(String annotationName); @Nullable MultiValueMap getAllAnnotationAttributes(String annotationName, boolean classValuesAsString);
3.1@AutoWired 注解只可以裝配只有一個(gè)實(shí)現(xiàn)類的Bean
例如下面的Dessert有三個(gè)實(shí)現(xiàn)類,自動(dòng)裝配時(shí),Spring就會(huì)不知道選哪一個(gè),因而會(huì)報(bào)NoUniqueBeanDefinitionException錯(cuò)誤。
public interface Dessert { } @Component public class Cake implements Dessert { } @Component public class Cookies implements Dessert { } @Component public class IceCream implements Dessert { } @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = CakeConfig.class) public class CakeTest { @Autowired private Dessert dessert;//Spring: emmm.... I don"t which one to choose @Test public void getDessert(){ assertNotNull(dessert); } }
3.2 @Primary 可以指定某個(gè)實(shí)現(xiàn)類作為優(yōu)先Bean創(chuàng)建
給蛋糕加個(gè)@Primary,表明首選蛋糕作為首選項(xiàng)。然后在執(zhí)行Test,發(fā)現(xiàn)就不抱錯(cuò)了。
@Primary可以配合@Component, @Bean, @Autowired使用。
@Component @Primary public class Cake implements Dessert { }
3.3 @Qualifie將使用的Bean限定到具體的實(shí)現(xiàn)類
由于@Qualifier是基于字符串去匹配Bean id的,所以你修改了類名就可能導(dǎo)致找不到對(duì)應(yīng)的Bean了。但我嘗試了一下,如果使用IDEA的Refactor->Rename,會(huì)幫我們自動(dòng)更改多處的。
@Qualifie可以配合@Component, @Bean, @Autowired使用。
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = CakeConfig.class) public class CakeTest { @Autowired @Qualifier("cookies") private Dessert dessert; @Test public void getDessert(){ assertNotNull(dessert); } }
Spring實(shí)戰(zhàn)中,為了解決@Qualifier“不夠用”,拼命地建立自定義注解,我感覺是沒有必要,有點(diǎn)畫蛇添足的感覺。
四. bean的作用域四種不同的作用域
單例(Singleton默認(rèn)):在整個(gè)應(yīng)用中,只創(chuàng)建bean的一個(gè)實(shí)例。
比如
@Bean @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) public Notepad notepad() { return new Notepad(); }
原型(Prototype):每次注入或者通過spring應(yīng)用上下文獲取的時(shí)候,都會(huì)創(chuàng)建一個(gè)新的bean實(shí)例。
比如:
@Bean @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public Notepad notepad() { return new Notepad(); }
會(huì)話(Session):在web應(yīng)用中,為每個(gè)會(huì)話創(chuàng)建一個(gè)bean實(shí)例, 舉個(gè)例子:
@Bean @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS) public Notepad notepad() { return new Notepad(); }
請(qǐng)求(Request):在web應(yīng)用中,為每個(gè)請(qǐng)求創(chuàng)建一個(gè)bean實(shí)例,舉個(gè)栗子:
@Bean @Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS) public Notepad notepad() { return new Notepad(); }
這里需要注意的是proxyMode這個(gè)屬性。(TODO:通過例子加深理解)
當(dāng)值為ScopedProxyMode.TARGET_CLASS時(shí),表示的該bean類型是具體類,只能使用CGLib來生成基于類的代理。
當(dāng)值為ScopedProxyMode.INTERFACES時(shí)。
1.使用@PropertySource, @Environment注入外部值
app.properties的內(nèi)容 disc.title=Sgt. Peppers Lonely Hearts Club Band disc.artist=The Beatles public class BlankDisc { private final String title; private final String artist; public BlankDisc(String title, String artist){ this.title = title; this.artist = artist; } public String getArtist() { return artist; } public String getTitle() { return title; } } @Configuration @PropertySource("classpath:/externals/com/soundsystem/app.properties") public class EnvironmentConfig { @Autowired private Environment env; @Bean public BlankDisc blankDisc(){ return new BlankDisc(env.getProperty("disc.title"), env.getProperty("disc.artist")); } }
另外Environment的getProperty有4個(gè)重載方式可以選擇
String getProperty(String key); //獲取指定key的內(nèi)容;如果找不到key就返回null String getProperty(String key, String defaultValue);//獲取指定key的內(nèi)容;如果找不到key,就返回默認(rèn)值T getProperty(String key, Class targetType);//targetType用于說明該key的值類型 T getProperty(String key, Class targetType, T defaultValue);
2.屬性占位符
${...}表示屬性占位符,常配合@Value使用,舉個(gè)栗子。
@Bean public BlankDisc blankDisc2(@Value("${disc.title}") String title, @Value("${disc.artist}")String artist){ return new BlankDisc(title, artist); }3.使用Spring表達(dá)式語言進(jìn)行裝配
1.使用bean的id來引用Bean TODO 待補(bǔ)充實(shí)例
2.調(diào)用方法和訪問對(duì)象的屬性
3.對(duì)峙進(jìn)行算數(shù),關(guān)系和邏輯運(yùn)算
4.正則表達(dá)式匹配
5.集合操作
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/76963.html
摘要:在集成測(cè)試時(shí),通常想要激活的是開發(fā)環(huán)境的。因?yàn)闆]有耦合類名,因此可以隨意重構(gòu)的類名,不必?fù)?dān)心破壞自動(dòng)裝配。在裝配中,占位符的形式為使用包裝的屬性名稱。參數(shù)裝配的是名為的屬性值。 環(huán)境與profile 配置profile bean 在3.1版本中,Spring引入了bean profile的功能。使用profile,首先將所有不同的bean定義整理到一個(gè)或多個(gè)profile之中,再將應(yīng)用...
摘要:甲乙交易活動(dòng)不需要雙方見面,避免了雙方的互不信任造成交易失敗的問題。這就是的核心思想。統(tǒng)一配置,便于修改。帶參數(shù)的構(gòu)造函數(shù)創(chuàng)建對(duì)象首先,就要提供帶參數(shù)的構(gòu)造函數(shù)接下來,關(guān)鍵是怎么配置文件了。 前言 前面已經(jīng)學(xué)習(xí)了Struts2和Hibernate框架了。接下來學(xué)習(xí)的是Spring框架...本博文主要是引入Spring框架... Spring介紹 Spring誕生: 創(chuàng)建Spring的...
摘要:高級(jí)裝配條件化的自動(dòng)裝配與歧義性的作用域表達(dá)式語言環(huán)境與可以為不同的環(huán)境提供不同的數(shù)據(jù)庫配置加密算法等注解可以在類級(jí)別和方法級(jí)別,沒有指定的始終都會(huì)被創(chuàng)建的方式配置不同環(huán)境所需要的數(shù)據(jù)庫配置會(huì)搭建一個(gè)嵌入式的數(shù)據(jù)庫模式定義在測(cè)試數(shù)據(jù)通過加 高級(jí)裝配 Spring profile 條件化的bean 自動(dòng)裝配與歧義性 bean的作用域 Spring表達(dá)式語言 環(huán)境與profile p...
摘要:原文地址運(yùn)行時(shí)注入與硬編碼注入是相對(duì)的。硬編碼注入在編譯時(shí)就已經(jīng)確定了,運(yùn)行時(shí)注入則可能需要一些外部的參數(shù)來解決。提供的兩種在運(yùn)行時(shí)求值的方式屬性占位符表達(dá)式語言注入外部的值使用注解可以引入文件,使用其中的值。 原文地址:http://blog.gaoyuexiang.cn/Sp... 運(yùn)行時(shí)注入與硬編碼注入是相對(duì)的。硬編碼注入在編譯時(shí)就已經(jīng)確定了,運(yùn)行時(shí)注入則可能需要一些外部的參數(shù)來...
摘要:裝配任何一個(gè)成功的應(yīng)用都是由多個(gè)為了實(shí)現(xiàn)某個(gè)業(yè)務(wù)目標(biāo)而相互協(xié)作的組件構(gòu)成的創(chuàng)建應(yīng)用對(duì)象之間協(xié)作關(guān)系的行為通常稱為裝配,這也是依賴注入配置的可選方案在中進(jìn)行顯示配置在中進(jìn)行顯示配置隱式的發(fā)現(xiàn)機(jī)制和自動(dòng)裝配自動(dòng)化裝配組件掃描會(huì)自動(dòng)發(fā)現(xiàn)應(yīng)用上下文 裝配Bean 任何一個(gè)成功的應(yīng)用都是由多個(gè)為了實(shí)現(xiàn)某個(gè)業(yè)務(wù)目標(biāo)而相互協(xié)作的組件構(gòu)成的 創(chuàng)建應(yīng)用對(duì)象之間協(xié)作關(guān)系的行為通常稱為裝配(wiring)...
閱讀 2584·2021-11-25 09:43
閱讀 1858·2021-09-22 15:26
閱讀 3735·2019-08-30 15:56
閱讀 1712·2019-08-30 15:55
閱讀 1897·2019-08-30 15:54
閱讀 814·2019-08-30 15:52
閱讀 3156·2019-08-29 16:23
閱讀 895·2019-08-29 12:43