Spring实战笔记——Bean的高级装配

上一章主要讲了Spring中Bean的基本装配,包括JavaConfig和XML,以及二者混合使用的方法,本章继续讲解Bean的一些高级装配方法。

本章内容:

  1. Spring profile
  2. 条件化的bean声明
  3. 自动装配与歧义性
  4. bean的作用域

1,Spring profile

在不同的环境中,我们创建某个bean的方式可能不同,比如,在开发阶段,我们可能使用集成的数据库作为DataSource,而在生产阶段则使用不同的DataSource。Spring为这种环境迁移带来的问题提供了很好的解决方案。Spring并不是在构建的时候决定该创建哪个bean或不创建哪个bean,而是在运行的时候再来确定。因此,同一个部署单元(可能是一个WAR包)能够适用于所有的环境。

Spring使用注解@Profile来确定Bean是否被创建。只有当@Profile中的profile激活时bean才会创建,如果没有激活,带有@Bean注解的方法都会被忽略掉

在Spring3.1中,只能在类级别上使用@Profile, 从Spring3.2开始,可以在方法级别上使用@Profile注解。

package com.example.config;

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")     //只有dev profile激活时这个bean才会创建,用于开发环境
    public DataSource embeddedDataSource() {
        return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2)
                .addScript("classpath:schema.sql")
                .addScript("classpath:test-data.sql")
                .build();
    }

    @Bean
    @Profile("prod")    //prod profile激活时,bean才会创建,用于生产环境
    public DataSource jndiDataSource() {
        JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean();
        jndiObjectFactoryBean.setJndiName("jdbc/myDs");
        jndiObjectFactoryBean.setResourceRef(true);
        jndiObjectFactoryBean.setProxyInterface(javax.sql.DataSource.class);
        return (DataSource)jndiObjectFactoryBean.getObject();
    }
}

使用XML配置的方式本文不再讲解。

激活Profile

Spring依靠spring.profiles.active和spring.profiles.default来确定哪个profile处于激活状态。如果设置了spring.profiles.active属性的话,它的值就会用来确定哪个profile是激活的;没有设置的话,spring就会查找spring.profiles.default。

有多种方式来设置者两个属性:

  1. 作为DispatcherServlet的初始化参数;
  2. 作为Web应用的上下文参数;
  3. 最为JNDI条目;
  4. 作为环境变量;
  5. 作为JVM的系统属性;
  6. 在集成测试类上,使用@ActiveProfiles注解设置。

Spring4中条件化的bean

@Conditional注解可以用来给bean的创建设置条件,必须满足条件bean才会创建。

解决自动装配的歧义性

Spring提供了多种可选方案来解决装配bean时的歧义性,可以将可选bean中的某一个设为首选(primary)的bean,或者使用限定符(qualifier)来帮助Spring将可选的bean的范围缩小到只有一个bean。

标示首选的bean:

@Component
@Primary
public class BlankDisc implements CompactDisc{ ... }

或者在JavaConfig中显示地声明BlankDisc:

@Bean
@primary
public BlankDisc blankDisc() {
    return new BlankDisc();
}

使用XML配置

<bean id="blankDisc" class="com.example.chr1s.BlankDisc" primary="true" />

当标识了多个首选bean时,还可以使用限定符来限定bean,限定符的功能更加强大,也更通用。

@Qualifier注解可以与@Autowired和@Inject注解系统使用。@Qualifier注解还有很多高级的应用,但是这些应用在实际开发中使用到的比较少,本文不再详述。

@Autowired
@Qualifier("blankDisc")
public void setDisc(CompactDisc compactDisc){
    disc = compactDisc;
}

为@Qualifier注解设置的参数就是想要注入的bean的id。

bean的作用域

默认情况下,Spring应用上下文中所有的bean都是作为以单例的形式创建的。也就是说,不管给定的一个bean被注入到其他bean多少次,每次所注入的都是同一个实例。

单例形式不是线程安全的,在很多场合下不适用。Spring还定义了多种作用域,可以基于这些作用域创建bean,包括:

  1. 单例(Singleton):在整个应用中,只有bean的一个实例;
  2. 原型(Prototype):在每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例;
  3. 会话(Session):在Web应用中,为每个会话创建一个bean实例;
  4. 请求(Request):在Web引用中,为每个请求创建一个实例。

要选择不同的作用域,应该使用@Scope注解。

@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class NotePad { ... }

将bean的作用域声明为prototype。

也可以在配置文件中声明作用域

@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public NotePad notePad() {
    return new NotePad();
}

@Scope有一个proxyMode属性,解决了将会话作用域的bean注入到单例bean中所遇到的问题。后面会进行更加详细的讲解。

Spring运行时值注入

Spring提供两种在运行时求值的方法:

  1. 属性占位符(Property PlaceHolder)
  2. Spring表达式语言(SpEL)

注入外部的值

可以通过声明属性源并通过Spring的Environment来检索属性,可以使用@PropertySource和Environment来实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值