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章