3. 高级装配
Spring profile
条件化 Bean 声明式
自动装配
Bean 作用域
Spring 表达式语言
3.1 Spring profile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| @Configuration public class DataSourceConfig {
@Bean(destroyMethod="shutdown") @Profile("dev") public DataSource embeddedDataSource() { return new EmbeddedDatabaseBuilder() .setType(EmbeddedDataabaseType.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(); } }
|
不指定 profile 的 bean始终都会被创建
激活 profile 依赖 spring.profiles.active
和 spring.profiles.default
属性
有 active 的就用 active,没有的话用 default,两个都没有的话就没有激活的 profile
设置方式:
DispatherServlet 的初始化参数
Web 应用的上下文参数
JNDI 条目
环境变量
JVM 系统属性
int 测试类上用 @ActiveProfiles 注解
3.2 条件配置 Bean
1 2 3 4 5
| @Bean @Conditional(MagicExistsCondition.class) public MagicBean magicBean() { return new MagicBean(); }
|
1 2 3 4 5 6
| public class MagicExistsCondition implements Condition { public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { Environment env = context.getEnvironment(); return env.containsProperty("magic"); } }
|
3.3 自动装配的歧义性
如果同时存在多个 Bean 匹配结果的话自动装配失效, NoUniqueBeanDefinitionException
1 2 3 4
| @Autowired public void setDessert(Dessert dessert) { this.dessert = dessert; }
|
1 2 3 4 5 6 7 8 9
| @Component public class Cake implements Dessert { ... }
@Component public class Cookies implements Dessert { ... }
@Component public class IceCream implements Dessert { ... }
|
解决方式:primary bean, qualifier bean
1 2 3
| @Component @Primary public class IceCream implements Dessert { ... }
|
primary 只能同时存在一个
1 2 3 4 5
| @Autowired @Qualifier("iceCream") public void setDessert(Dessert dessert) { this.dessert = dessert }
|
限定符必须和要注入的 bean 名称紧耦合
所有使用 @Component 声明的类都会创建为 Bean,并且 Bean ID 首字母变为小写的类名
@Qualifier 也可以和 @Component 组合使用,自定义限定符
也可以创建自定义注解
1 2 3 4 5
| @Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Qualifier public @interface Cold { }
|
3.4 Bean 作用域
默认情况下 bean 是作为单例创建的,不管注入多少次都是同一个实例
如果类里面会保持某些状态,单例重用会比较麻烦,容易污染对象
作用域:
1 2 3
| @Bean @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class Notepad { ... }
|
3.5 运行时值注入
属性占位符 Property Placeholder
SpEL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Configuration @PropertySource("classpath:/com/soundsystem/app.properties") public class ExpressiveConfig {
@Autowired Environment env;
@Bean public BlankDisc disc() { return new BlankDisc( env.getProperty("disc.title"), env.getProperty("disc.artist") ) } }
|
getProperty 还可以用来在所需属性不存在的时候指定默认值
如果需要属性一定存在的话可以用 getRequiredProperty
1 2 3
| String getProperty(String key, String defaultValue)
T getProperty(String key, Class<T> type, T defaultValue)
|