Spring的Bean作用域 --《Spring In Action》
在默认情况下,Spring App上下文中所有Bean都是单例(singleton)的形式创建。不管给定的一个bean被注入多少次,每次所注入的都是同一个实例。
Bean 作用域
- 单例(Singleton):在整个应用中,只创建bean的一个实例(默认作用域)
- 原型(Prototype):每次注入或者通过Spring App上下文获取的时候都会创建新的bean实例
- 会话(Session):在Web应用中,为每个会话创建一个Bean实例
- 请求(Request):在Web应用中,为每个请求创建一个Bean实例
如何指定Bean的作用域
- 第一种方式在通过@Scope注解
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Notepad notepad(){
return new Notepad();
}
- 第二种方式在XML配置作用域
<bean id="notepad" class="com.myapp.Notepad" scope="prototype"/>
使用会话和请求作用域
在Web应用中,如电子商务应用中的购物车Bean如果是单例的话会导致所有用户都会向一个购物车中添加商品。另一个方面如果购物车是原型作用域在应用中其他的地方不会出现造成资源浪费。
@Component
@Scope(value=WebApplicationContext.SCOPE_SESSION, proxyMode=ScopedProxyMode.INTERFACES)
public ShoppingCart cart(){...}
// value=WebApplicationContext.SCOPE_SESSION : 表明Spring为Web应用中的每个会话创建一个ShoppingCart
// proxyMode=ScopedProxyMode.INTERFACES : 表明解决了将会话或请求作用域的bean注入到单例Bean中所遇到的问题
proxyMode=ScopedProxyMode.INTERFACES;
表明这个代理要实现ShoppingCart接口,并将调用委托给实现bean。如果Bean的类型就是具体类而不是接口则需要改变属性值proxyMode=ScopedProxyMode.TARGET_CLASS
来表明要以生成目标类扩展的方式创建代理。
作用域代理能够延迟注入请求和会话作用域的Bean
- 在XML中配置作用域
<bean id="cart" class="com.myapp.ShoppingCart" scope="session">
<aop:aspect-proxy proxy-target-class="false"/>
</bean>
实现运行时注入
- 传统“硬编码”注入方式
//- Java中
@Bean
public CompactDisc sgtPeppers(){
return new BlankDisc("Sgt, Pepper's Lonely", "The Beatles");
}
// - XML中
<bean id="sgtPeppers"
class="soundsystem.BlankDisc"
c:_title="xxx"
c:_artist="xxx"/>
Spring提供两种运行时注入值的方式
注入外部值
@Configuration
@PropertySource("classpath:/com/soundsystem/app.properties") // 声明属性源
public class BlankDisc{
@Autowired
Environment env;
@Bean
public BlankDisc disc(){
return new BlankDisc(env.getProperty("disc.title"),env.getProperty("disc.artist")); // 检索属性值
}
}
/**app.properties
disc.title="xxx"
disc.artist="xxx"
*/
Spring的Environment中存在四种getProperty()重载的变种形式
- String getProperty(String key)
- String getProperty(String key, String defaultValue)
- T getProperty(String key, Class
type) - T getProperty(String key, Class
type, T defaultValue)
属性占位符(Property placeholder)
// XML 设置
<bean id="sgtPeppers" class="soundsystem.BlankDisc" c:_title="${disc.title}" c:_artist="${disc.artist}"/>
// Java 设置
public BlankDisc{@Value("${disc.title}") String title, @Value("${disc.artist}") String artist){
this.title = title;
this.artist = artist;
}
// 在web.xml中开启SpEL
<context:property-placeholder/>
学而不思则罔,思而不学则殆!