February 20, 2022

Spring @Scope Annotation

Spring container not only instantiates a bean and wire its dependencies it also provides the scope of an instance. There is inbuilt support for six bean scopes in Spring Framework. For example, bean scope can be singleton, prototype and so forth. This post shows how to set a bean scope using Spring @Scope annotation.

Supported Spring bean scopes

  • Singleton scope– Single object instance corresponding to a bean definition is created for each Spring IoC container. Singleton scope is a default bean scope.
  • Prototype scope– New object instance is created every time bean is requested from the Spring container.
  • Request scope– For each HTTP request new bean instance is created. This Spring bean scope is valid only in the context of a web-aware Spring ApplicationContext.
  • Session scope– Single bean instance is scoped to the lifecycle of an HTTP Session. This scope is valid only in the context of a web-aware Spring ApplicationContext.
  • Application scope– Scopes a single bean definition to the lifecycle of a ServletContext. This scope is valid only in the context of a web-aware Spring ApplicationContext.
  • Websocket scope– Scopes a single bean definition to the lifecycle of a WebSocket. This scope is valid only in the context of a web-aware Spring ApplicationContext.

Where to use @Scope Annotation

@Scope annotation can be used used as a type-level annotation in conjunction with @Component and @Configuration annotations. When used as a type-level annotation, @Scope indicates the name of a scope to use for instances of the annotated type.

@Scope annotation can also be used used as a method-level annotation in conjunction with @Bean. When used as a method-level annotation @Scope indicates the name of a scope to use for the instance returned from the method.

@Scope annotation with different scopes

In this section we'll see code snippets of using @Scope annotation with different bean scopes. Scopes provided out of the box in Spring may be referred to using the SCOPE_* constants available in the ConfigurableBeanFactory and WebApplicationContext interfaces.

@Scope with Singleton bean scope
@Service
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public class BeanService{
 ...
 ...
}
@Scope with Prototype bean scope
@Service
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class BeanService{
 ...
 ...
}
@Scope with Request bean scope
@Service
@Scope(WebApplicationContext.SCOPE_REQUEST)
public class BeanService{
 ...
 ...
}
@Scope with Session bean scope
@Service
@Scope(WebApplicationContext.SCOPE_SESSION)
public class BeanService{
 ...
 ...
}
@Scope with Application bean scope
@Service
@Scope(WebApplicationContext.SCOPE_APPLICATION)
public class BeanService{
 ...
 ...
}
@Scope with WebSocket bean scope
@Component
@Scope(scopeName = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyBean {
 ...
 ...
}

Spring @Scope annotation Singleton example

Defining a bean with singleton scope means single instance of that bean is created by the container. All the requests for that bean will return the same object and any modifications to the field will be reflected in all references to the bean as all references point to the same object.

Singleton scope is the default bean scope if no scope is explicitly specified.

We have a User class with fields like firstName, lastName and age. Class is annotated with @Scope annotation with scope specified as singleton.

@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;
  }
} 

App config class to specify component scanning.

@Configuration
@ComponentScan("com.knpcode.springexample")
public class AppConfig {

}

Now if you run this example and get two objects of User bean from the container both object reference will point to the same bean as the scope is singleton.

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();
  }
}
Output
First Name- Ray
Last Name- Chandler

As you can see firstName and lastName are set using the user1 reference, getting and printing the values of these fields from user2 reference also give the same values.

Spring @Scope annotation Prototype example

In the User class as showed above if scope is changed to Prototype.

@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class User {
  private String firstName;
  private String lastName;
  ...
  ...
}

Run the example now and analyze the output.

First Name- null
Last Name- null

Fields are still null for user2 instance as separate instance is created now because of the prototype scope.

Spring @Scope annotation with @Configuration

In the above example @Scope is used in conjunction with @Component, let’s see an example where @Scope is used with @Configuration and @Bean annotations.

Here are two classes whose instances will be returned from the methods annotated with @Bean methods.

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");
  }
}
Config class

In the config class @Scope is used as both type-level annotation and method-level annotation. At the type level (in conjunction with @Configuration) scope is specified as prototype.

At the method level with one method no scope is specified which means bean will have default level Singleton. Note that Scope specified at the type level is not applicable to the method level automatically, methods will have its own scope. Another method has the scope Prototype.

@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();
  }
}

We can check the scopes of the bean by getting the BeanDefinition instance which has methods isSingleton and isPrototype.

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();
  }
}
Output
AppConfig has prototype scope- true
MyBean has prototype scope- false
MyBean has singleton scope- true
ClassB has prototype scope- true

From the output you can see that the scope for AppConfig bean is prototype, that’s what we defined at type level.

Scope for MyBean instance is Singleton which is assigned by default. Scope for ClassB instance is prototype as defined at the method level in the Config class.

That's all for the topic Spring @Scope Annotation. If something is missing or you have something to share about the topic please write a comment.


You may also like

No comments:

Post a Comment