Spring @Scope批注
Spring容器不仅实例化bean并连接其依赖关系,还提供实例的范围。在Spring Framework中对六个bean作用域有内在的支持。例如,bean作用域可以是单例,原型等。这篇文章展示了如何使用Spring @Scope注释设置bean范围。
Spring bean支持的作用域
单例作用域–为每个Spring IoC容器创建一个与bean定义相对应的单个对象实例。 Singleton范围是默认的bean范围。
原型作用域–每次从Spring容器请求bean时都会创建一个新的对象实例。
请求范围–为每个HTTP请求创建一个新的bean实例。此Spring bean范围仅在可感知网络的Spring ApplicationContext的上下文中有效。
会话范围–单个bean实例的范围是HTTP会话的生命周期。该范围仅在可感知网络的Spring ApplicationContext的上下文中有效。
应用程序范围–将单个bean定义范围限定为ServletContext的生命周期。该范围仅在可感知网络的Spring ApplicationContext的上下文中有效。
Websocket范围–将单个bean定义的范围扩展到WebSocket的生命周期。该范围仅在可感知网络的Spring ApplicationContext的上下文中有效。
在哪里使用@Scope注释
@Scope批注可以与@Component和@Configuration批注一起用作类型级别的批注。当用作类型级注释时,@ Scope表示要用于带注释类型的实例的范围的名称。
@Scope注释还可以与@Bean一起用作方法级注释。 @Scope用作方法级注释时,@ Scope表示要用于从方法返回的实例的范围的名称。
具有不同范围的@Scope批注
在本部分中,我们将看到将@Scope注释与不同的bean范围一起使用的代码段。可以使用ConfigurableBeanFactory和WebApplicationContext接口中可用的SCOPE_ *常量来引用Spring中开箱即用的范围。
@Scope与Singleton bean范围
@Service
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public class BeanService{
...
...
}
@Scope与原型bean范围
@Service
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class BeanService{
...
...
}
@Scope与请求bean范围
@Service
@Scope(WebApplicationContext.SCOPE_REQUEST)
public class BeanService{
...
...
}
@Scope与会话bean范围
@Service
@Scope(WebApplicationContext.SCOPE_SESSION)
public class BeanService{
...
...
}
@Scope与应用程序bean范围
@Service
@Scope(WebApplicationContext.SCOPE_APPLICATION)
public class BeanService{
...
...
}
WebScope bean作用域的@Scope
@Component
@Scope(scopeName = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyBean {
...
...
}
Spring @Scope批注Singleton示例
用单例作用域定义一个bean意味着该bean的单个实例是由容器创建的。对于该bean的所有请求都将返回相同的对象,并且对该字段的任何修改将反映在该bean的所有引用中,因为所有引用都指向同一对象。
如果未明确指定范围,则Singleton范围是默认的bean范围。
我们有一个User类,其中包含firstName,lastName和age等字段。用@Scope批注对类进行批注,范围指定为单例。
@Component
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public class User {
private String firstName;
private String lastName;
private int age;
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public int getAge() {
return age;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public void setAge(int age) {
this.age = age;
}
}
应用程序配置类,用于指定组件扫描。
@Configuration
@ComponentScan("com.theitroad.springexample")
public class AppConfig {
}
现在,如果我们运行此示例并从容器中获取User Bean的两个对象,则两个对象引用将指向同一bean,因为作用域为单例。
public class App {
public static void main(String[] args) {
AbstractApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
User user1 = context.getBean("user", User.class);
User user2 = context.getBean("user", User.class);
user1.setFirstName("Ray");
user1.setLastName("Chandler");
System.out.println("First Name- " + user2.getFirstName());
System.out.println("Last Name- " + user2.getLastName());
context.close();
}
}
输出:
First Name- Ray Last Name- Chandler
如我们所见,firstName和lastName是使用user1引用设置的,从user2引用获取和打印这些字段的值也提供相同的值。
Spring @Scope注释原型示例
如果范围更改为原型,则在上面显示的User类中。
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class User {
private String firstName;
private String lastName;
...
...
}
现在运行示例并分析输出。
First Name- null Last Name- null
由于原型范围,现在创建了单独的实例,因此user2实例的字段仍然为null。
使用@Configuration的Spring @Scope批注
在上面的示例中,@ Scope与@Component结合使用,让我们看一个示例,其中@Scope与@Configuration和@Bean批注一起使用。
这是两个类,其实例将从使用@Bean方法注释的方法中返回。
public class MyBean {
public void myMethod() {
System.out.println("In MyMethod of MyBean class");
}
}
public class ClassB {
public ClassB(){
System.out.println("In constructor of ClassB");
}
}
配置类
在配置类中,@Scope用作类型级注释和方法级注释。在类型级别(结合@Configuration),范围被指定为原型。
在使用一种方法的方法级别上,未指定范围,这意味着Bean将具有默认级别的Singleton。请注意,在类型级别指定的范围不适用于自动方法级别,方法将具有自己的范围。另一种方法具有范围原型。
@Configuration
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class AppConfig {
@Bean
public MyBean myBean() {
return new MyBean();
}
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public ClassB classB() {
return new ClassB();
}
}
我们可以通过获取具有方法isSingleton和isPrototype的BeanDefinition实例来检查bean的范围。
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
System.out.println("AppConfig has prototype scope- " + context.getBeanDefinition("appConfig").isPrototype());
System.out.println("MyBean has prototype scope- " + context.getBeanDefinition("myBean").isPrototype());
System.out.println("MyBean has singleton scope- " + context.getBeanDefinition("myBean").isSingleton());
System.out.println("ClassB has prototype scope- " + context.getBeanDefinition("classB").isPrototype());
context.close();
}
}
输出:
AppConfig has prototype scope- true MyBean has prototype scope- false MyBean has singleton scope- true ClassB has prototype scope- true
从输出中,我们可以看到AppConfig bean的作用域是原型,这就是我们在类型级别上定义的范围。
MyBean实例的范围是默认情况下分配的Singleton。 ClassB实例的范围是在Config类的方法级别定义的原型。

