摘要:注解只可以裝配只有一個實現(xiàn)類的例如下面的有三個實現(xiàn)類,自動裝配時,就會不知道選哪一個,因而會報錯誤。使用表達式語言進行裝配使用的來引用待補充實例調(diào)用方法和訪問對象的屬性對峙進行算數(shù),關(guān)系和邏輯運算正則表達式匹配集合操作
完整代碼請見:https://github.com/codercuixi...
第一部分 @Profile注解的使用環(huán)境與profile 是否啟用某個bean,常用于數(shù)據(jù)庫bean
通過profile啟用不同的bean,特別是對于各種不同的數(shù)據(jù)庫(開發(fā)線,測試線,正式線),尤其管用。
1.1第一步 配置profile bean。通過@Profile修飾類或者方法名,來表明這個Bean是可以動態(tài)啟動與否的
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.通過兩個參數(shù)激活profile
spring.profiles.active和spring.profiles.default,優(yōu)先使用前者的配置。
設置這兩個參數(shù)的方式有如下幾種:(待補充完整)
作為DIspatcherServlet的初始化參數(shù)
作為Web應用的上下文參數(shù)
作為JNDI條目
作為環(huán)境變量
作為JVM的系統(tǒng)屬性
在集成測試類上,使用@ActiveProfile注解設置。(也就是上面第二步演示的)
第二部分 條件化的bean通過@Conditional, 可以用到Bean上,當條件為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)應用到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(); } }
由于實現(xiàn)了match方法中帶有兩個參數(shù),我們可以通過這兩個參數(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第三部分 處理自動裝配的歧義性。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 注解只可以裝配只有一個實現(xiàn)類的Bean
例如下面的Dessert有三個實現(xiàn)類,自動裝配時,Spring就會不知道選哪一個,因而會報NoUniqueBeanDefinitionException錯誤。
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 可以指定某個實現(xiàn)類作為優(yōu)先Bean創(chuàng)建
給蛋糕加個@Primary,表明首選蛋糕作為首選項。然后在執(zhí)行Test,發(fā)現(xiàn)就不抱錯了。
@Primary可以配合@Component, @Bean, @Autowired使用。
@Component @Primary public class Cake implements Dessert { }
3.3 @Qualifie將使用的Bean限定到具體的實現(xiàn)類
由于@Qualifier是基于字符串去匹配Bean id的,所以你修改了類名就可能導致找不到對應的Bean了。但我嘗試了一下,如果使用IDEA的Refactor->Rename,會幫我們自動更改多處的。
@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實戰(zhàn)中,為了解決@Qualifier“不夠用”,拼命地建立自定義注解,我感覺是沒有必要,有點畫蛇添足的感覺。
四. bean的作用域四種不同的作用域
單例(Singleton默認):在整個應用中,只創(chuàng)建bean的一個實例。
比如
@Bean @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) public Notepad notepad() { return new Notepad(); }
原型(Prototype):每次注入或者通過spring應用上下文獲取的時候,都會創(chuàng)建一個新的bean實例。
比如:
@Bean @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public Notepad notepad() { return new Notepad(); }
會話(Session):在web應用中,為每個會話創(chuàng)建一個bean實例, 舉個例子:
@Bean @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS) public Notepad notepad() { return new Notepad(); }
請求(Request):在web應用中,為每個請求創(chuàng)建一個bean實例,舉個栗子:
@Bean @Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS) public Notepad notepad() { return new Notepad(); }
這里需要注意的是proxyMode這個屬性。(TODO:通過例子加深理解)
當值為ScopedProxyMode.TARGET_CLASS時,表示的該bean類型是具體類,只能使用CGLib來生成基于類的代理。
當值為ScopedProxyMode.INTERFACES時。
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個重載方式可以選擇
String getProperty(String key); //獲取指定key的內(nèi)容;如果找不到key就返回null String getProperty(String key, String defaultValue);//獲取指定key的內(nèi)容;如果找不到key,就返回默認值T getProperty(String key, Class targetType);//targetType用于說明該key的值類型 T getProperty(String key, Class targetType, T defaultValue);
2.屬性占位符
${...}表示屬性占位符,常配合@Value使用,舉個栗子。
@Bean public BlankDisc blankDisc2(@Value("${disc.title}") String title, @Value("${disc.artist}")String artist){ return new BlankDisc(title, artist); }3.使用Spring表達式語言進行裝配
1.使用bean的id來引用Bean TODO 待補充實例
2.調(diào)用方法和訪問對象的屬性
3.對峙進行算數(shù),關(guān)系和邏輯運算
4.正則表達式匹配
5.集合操作
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/76963.html
摘要:在集成測試時,通常想要激活的是開發(fā)環(huán)境的。因為沒有耦合類名,因此可以隨意重構(gòu)的類名,不必擔心破壞自動裝配。在裝配中,占位符的形式為使用包裝的屬性名稱。參數(shù)裝配的是名為的屬性值。 環(huán)境與profile 配置profile bean 在3.1版本中,Spring引入了bean profile的功能。使用profile,首先將所有不同的bean定義整理到一個或多個profile之中,再將應用...
摘要:甲乙交易活動不需要雙方見面,避免了雙方的互不信任造成交易失敗的問題。這就是的核心思想。統(tǒng)一配置,便于修改。帶參數(shù)的構(gòu)造函數(shù)創(chuàng)建對象首先,就要提供帶參數(shù)的構(gòu)造函數(shù)接下來,關(guān)鍵是怎么配置文件了。 前言 前面已經(jīng)學習了Struts2和Hibernate框架了。接下來學習的是Spring框架...本博文主要是引入Spring框架... Spring介紹 Spring誕生: 創(chuàng)建Spring的...
摘要:高級裝配條件化的自動裝配與歧義性的作用域表達式語言環(huán)境與可以為不同的環(huán)境提供不同的數(shù)據(jù)庫配置加密算法等注解可以在類級別和方法級別,沒有指定的始終都會被創(chuàng)建的方式配置不同環(huán)境所需要的數(shù)據(jù)庫配置會搭建一個嵌入式的數(shù)據(jù)庫模式定義在測試數(shù)據(jù)通過加 高級裝配 Spring profile 條件化的bean 自動裝配與歧義性 bean的作用域 Spring表達式語言 環(huán)境與profile p...
摘要:原文地址運行時注入與硬編碼注入是相對的。硬編碼注入在編譯時就已經(jīng)確定了,運行時注入則可能需要一些外部的參數(shù)來解決。提供的兩種在運行時求值的方式屬性占位符表達式語言注入外部的值使用注解可以引入文件,使用其中的值。 原文地址:http://blog.gaoyuexiang.cn/Sp... 運行時注入與硬編碼注入是相對的。硬編碼注入在編譯時就已經(jīng)確定了,運行時注入則可能需要一些外部的參數(shù)來...
摘要:裝配任何一個成功的應用都是由多個為了實現(xiàn)某個業(yè)務目標而相互協(xié)作的組件構(gòu)成的創(chuàng)建應用對象之間協(xié)作關(guān)系的行為通常稱為裝配,這也是依賴注入配置的可選方案在中進行顯示配置在中進行顯示配置隱式的發(fā)現(xiàn)機制和自動裝配自動化裝配組件掃描會自動發(fā)現(xiàn)應用上下文 裝配Bean 任何一個成功的應用都是由多個為了實現(xiàn)某個業(yè)務目標而相互協(xié)作的組件構(gòu)成的 創(chuàng)建應用對象之間協(xié)作關(guān)系的行為通常稱為裝配(wiring)...
閱讀 2577·2021-11-25 09:43
閱讀 1849·2021-09-22 15:26
閱讀 3697·2019-08-30 15:56
閱讀 1703·2019-08-30 15:55
閱讀 1889·2019-08-30 15:54
閱讀 806·2019-08-30 15:52
閱讀 3135·2019-08-29 16:23
閱讀 886·2019-08-29 12:43