import javax.sql.DataSource; import org.apache.commons.dbcp.BasicDataSource; import org.springframework.context.annotation.Bean; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; import org.springframework.jndi.JndiObjectFactoryBean; /** * 不一樣環境所須要的數據庫配置 */ public class DataSourceDemo { /** * EmbeddedDatabaseBuilder會搭建一個嵌入式的Hypersonic數據庫 * 模式(schema)定義在schema.sql * 測試數據經過test-data.sql加載 */ @Bean(destroyMethod="shutdown") public DataSource dataSource_1(){ return new EmbeddedDatabaseBuilder() .addScript("classpath:schema.sql") .addScript("classpath:test-data.sql") .build(); } /** * 使用JNDI從容器中獲取一個DataSource */ @Bean public DataSource dataSource_2(){ JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean(); jndiObjectFactoryBean.setJndiName("jdbc/myDs"); jndiObjectFactoryBean.setResourceRef(true); jndiObjectFactoryBean.setProxyInterface(javax.sql.DataSource.class); return (DataSource) jndiObjectFactoryBean.getObject(); } /** * 配置DBCP的鏈接池 */ @Bean(destroyMethod="close") public DataSource dataSource(){ BasicDataSource dataSource = new BasicDataSource(); dataSource.setUrl("jdbc:h2:tcp://dbserver/~/test"); dataSource.setDriverClassName("org.h2.Driver"); dataSource.setUsername("root"); dataSource.setPassword("root"); dataSource.setInitialSize(20); dataSource.setMaxActive(30); return dataSource; } }
依賴屬性:spring.profiles.active和spring.profiles.defaultjava
import javax.sql.DataSource; 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; /** * 不一樣環境數據源部署配置類 * */ @Configuration public class DataSourceConfig { /** * 爲dev profile裝配的bean * @return */ @Bean(destroyMethod="shutdown") @Profile("dev") public DataSource embeddedDataSource(){ return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.H2) .addScript("classpath:schema.sql") .addScript("classpath:test-data.sql") .build(); } /** * 爲prod profile裝配的bean * @return */ @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(); } } import javax.sql.DataSource; 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; /** * 開發環境部署配置類 * */ @Configuration @Profile("dev") public class DevelopmentProfileConfig { @Bean(destroyMethod="shutdown") public DataSource dataSource(){ return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.H2) .addScript("classpath:schema.sql") .addScript("classpath:test-data.sql") .build(); } } import org.junit.runner.RunWith; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * 使用profile進行測試 * 當運行集成測試時,Spring提供了@ActiveProfiles註解,使用它來指定運行測試時要激活哪一個profile * */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes={PersistenceConfig.class}) @ActiveProfiles("dev") public class PersistenceTest { }
經過ConditionContext,能夠:web
@Profile這個註解自己也使用了@Conditional註解,而且引用ProfileCondition做爲條件正則表達式
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 MagicExistsConditional implements Condition { /** * 方法簡單功能強大 */ @Override public boolean matches(ConditionContext ctxt, AnnotatedTypeMetadata metadata) { Environment env = ctxt.getEnvironment(); //檢查magic屬性 return env.containsProperty("magic"); } }
標示首選(primary)的bean算法
限定自動裝配的beanspring
* 建立自定義的限定符sql
* 在@Component註解上加@Qualifier("selfDefinedName")註解 * 能夠在@Autowired上加@Qualifier("selfDefinedName") * 也能夠在Java配置顯示定義bean時,在@Bean註解上加@Qualifier("selfDefinedName")
使用自定義的限定符註解數據庫
Spring定義了多種做用域apache
使用會話和請求做用域數組
import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.ScopedProxyMode; import org.springframework.stereotype.Component; import org.springframework.web.context.WebApplicationContext; /** * value=WebApplicationContext.SCOPE_SESSION值是session,每一個會話會建立一個ShoppingCart * proxyMode=ScopedProxyMode.INTERFACES建立類的代理,確保當前購物車就是當前會話所對應的那一個,而不是其餘用戶 * * XML的配置 * <bean id="cart" class="com.leaf.u_spring.chapter03.ShoppingCart" scope="session"> * <aop:scoped-proxy /> * </bean> * * 使用的是CGLib生成代理類 */ @Component @Scope(value=WebApplicationContext.SCOPE_SESSION, proxyMode=ScopedProxyMode.INTERFACES) public class ShoppingCart { }
Spring提供兩種運行的值注入安全
深刻學習Spring的Environment
解析屬性佔位符
使用Spring表達式語言進行裝配
SpEl擁有特性:
* #{1} - 1 * #{T(System).currentTimeMillis()} -當前毫秒數 * #{sgtPeppers.artist} - ID爲sgtPeppers的bean的artist屬性 * #{systemProperties['disc.title']} -經過systemProperties對象引用系統屬性
* 表示字面值 * 浮點數:#{3.14159} 科學計數法:#{9.87E4} 字符串:#{'hello'} boolean類型:#{false} * 引入bean、屬性和方法
* #{sgtPeppers} -bean #{sgtPeppers.artist} -屬性 * #{sgtPeppers.selectArtist()} -方法 * #{sgtPeppers.selectArtist()?.toUpperCase()} -?.判斷非空狀況調用toUpperCase方法
* 在表達式中使用類型 * 若是要在SpEL中訪問類做用域的方法和常量的話,要依賴T()這個關鍵的運算符。 * 表達Java的Math類 T(java.lang.Math) * 把PI屬性裝配待bean屬性 T(java.lang.Math).PI * 調用T()運算符所獲得的靜態方法 T(java.lang.Math).random() * SpEL運算符
* 算術運算、比較運算、邏輯運算、條件運算、正則表達式、三元運算符 * #{2 * T(java.lang.Math).PI * circle.radius} -計算圓周長 * #{T(java.lang.Math).PI * circle.radius ^ 2} -計算圓面積 * #{disc.title + 'by' + disc.artist} -String類型的鏈接操做 * #{counter.total == 100}或#{counter.total eq 100} -比較運算 * #{scoreboard.score > 1000 ? 'Winner!' : 'Losser'} -三元運算 * #{disc.title ?: 'Rattle and Hum'} -檢查null,使用默認值代替null * #{admin.email matches '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.com'} -匹配有效郵箱 * #{jukebox.songs[4].title} -計算ID爲jukebox的bean的songs集合中第五個元素的title屬性 * #{jukebox.songs[T(java.lang.Math).random() * jukebox.songs.size].title} -獲取隨機歌曲的title * #{jukebox.songs.?[artist eq 'Aerosmith']} -用來對集合過濾查詢 * ‘.^[]’ 和 ‘.$[]’分別用來在集合中查詢第一個匹配項和最後一個匹配項 * 投影運算符 (.![]),會從集合的每一個成員中選擇特定的屬性放到另一個集合中
引用:《Spring In Action 4》第3章