在默认情况下,Spring应用上下文中所有的bean都是作为以单例的形式创建的。也就是说,不管给定的一个bean被注入到其他bean多少次,每次所注入的都是同一个实例。
Spring中定义了多种作用域,包括:
1、单例(Singleton):在整个应用中,只创建bean的一个实例.
2、原型(Prototype):每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例
3、会话(Session):在Web应用中,为每个会话创建一个bean实例
4、请求(request):在Web应用中,为每个请求创建一个bean实例
使用组件扫描来发现和声明bean:
@Component("lonely")
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
//@Scope("prototype") 也是可以的
public class SgtPeppers implements CompactDisc {
public void play() {
System.out.println("test");
}
}
在JavaConfig中设置作用域
@Configuration
public class DispactConfig {
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public CompactDisc compactDisc(){
return new SgtPeppers();
}
}
在XML中设置作用域:
<bean id="cdPlat" class="org.springaction.CDPlat" scope="prototype"/>
二、使用会话和请求作用域
@Component
@Scope(value="session",proxyMode = ScopedProxyMode.INTERFACES)
public class SgtPeppers implements CompactDisc {
public void play() {
System.out.println("test");
}
}
将value设置为session,会为Web应用中的每个会话创建一个bean的实例。
@Component
public class Instrument {
@Autowired
public void setSgtPeppers(CompactDisc sgtPeppers) {
this.sgtPeppers = sgtPeppers;
}
}
在被依赖的instrument bean,可能是一个单例的bean,它会在Spring应用上下文加载的时候创建,当它创建的时候,Spring会试图将会话范围的sgtPeppers bean注入到构造器或setter方法中,但是会话作用域范围的sgtPeppers bean此时并不存在,直到某个用户进入系统,创建了会话之后,才会出现。并且并不想让Spring注入某个固定的会话bean。所以需要配置proxyMode,使用代理的会话bean。当真正调用会话bean的方法时,代理会对其进行解析并将调用委托给会话作用域内真正的sgtPeppers bean。
proxyMode属性有两个值:
ScopedProxyMode.INTERFACES :如果会话bean是一个接口,该属性值表明这个代理要实现接口,并将调用委托给实现的bean。
ScopedProxyMode.TARGET_CLASS :如果会话Bean是一个具体的类,那就没办法创建基于接口的代理,需要使用该属性值,表明要以继承的方式创建代理。
请求作用域
请求作用域的bean也会遇到相同的装配问题,也应该使用作用域代理的方式进行注入:
@Component
@Scope(value="request",proxyMode =ScopedProxyMode.INTERFACES)
public class SgtPeppers implements CompactDisc {
public void play() {
System.out.println("test");
}
}
在XML中声明作用域代理
需要使用aop命名空间,
<bean id="sgtPeppers" class="org.springaction.SgtPeppers" scope="session">
<!--默认使用基于具体类的代理-->
<aop:scoped-proxy/>
</bean>
可以将proxy-target-class属性设置为false,要求它生成基于接口的代理:
<bean id="sgtPeppers" class="org.springaction.SgtPeppers" scope="session">
<!--默认使用基于具体类的代理-->
<aop:scoped-proxy proxy-target-class="false"/>
</bean>