📜  Java Spring 中的单例和原型 Bean 范围

📅  最后修改于: 2022-05-13 01:54:43.134000             🧑  作者: Mango

Java Spring 中的单例和原型 Bean 范围

Bean Scopes指的是 Bean 的生命周期,这意味着 Bean 的对象何时被实例化,该对象存在多长时间,以及在整个过程中将为该 bean 创建多少对象。基本上,它控制 bean 的实例创建,并由 spring 容器管理。
Spring 中的 Bean 作用域
spring 框架为一个 bean 提供了五个作用域。我们只能在 web 感知Spring ApplicationContext的上下文中使用其中的三个,其余的两个可用于IoC 容器和 Spring-MVC 容器。以下是为 bean 提供的不同范围:

  1. 单例:每个 Spring IoC 容器只会为单个 bean 定义创建一个实例,并且为对该 bean 发出的每个请求共享相同的对象。
  2. 原型:每次对该 bean 发出请求时,都会为单个 bean 定义创建一个新实例。
  3. 请求:每次对该 bean 发出 HTTP 请求时,都会为单个 bean 定义创建一个新实例。但仅在 Web 感知 Spring ApplicationContext 的上下文中有效。
  4. 会话:将单个 bean 定义限定为 HTTP 会话的生命周期。但仅在 Web 感知 Spring ApplicationContext 的上下文中有效。
  5. Global-Session:将单个 bean 定义限定为全局 HTTP 会话的生命周期。它也仅在 Web 感知 Spring ApplicationContext 的上下文中有效。

让我们详细看看其中的一些:

单例范围:

如果作用域是单例,那么每个 Spring IoC 容器只会实例化该 bean 的一个实例,并且每个请求都将共享同一个实例。也就是说,当一个 bean 的范围被声明为单例时,每当对该 bean 发出新请求时,spring IOC 容器首先检查该 bean 的实例是否已经创建。如果它已经创建,则 IOC 容器返回相同的实例,否则它仅在第一次请求时创建该 bean 的新实例。默认情况下,bean 的范围是单例。
让我们通过一个例子来理解这个范围。

  • Step1:让我们首先创建一个bean(即),它是spring框架中应用程序的主干。
Java
// Java program to illustrate a bean
// created in the spring framework
package bean;
 
public class HelloWorld {
    public String name;
 
    // Create a setter method to
    // set the value passed by user
    public void setName(String name)
    {
        this.name = name;
    }
 
    // Create a getter method so that
    // the user can get the set value
    public String getName()
    {
        return name;
    }
}


XML


     
     < bean
         id = "hw"
         class= "bean.HelloWorld"
         scope = "singleton" / >


Java
// Java program to illustrate
// the client to perform the
// request to the defined bean
 
package driver;
 
import org.springframework
    .context.ApplicationContext;
 
import org.springframework
    .context.support
    .ClassPathXmlApplicationContext;
 
import bean.HelloWorld;
 
// Client Class to request the
// above defined bean
public class Client {
 
    public static void main(String[] args)
    {
        // Load the Spring XML configuration
        // file into IoC container
        ApplicationContext
            ap
            = new ClassPathXmlApplicationContext(
                "resources/spring.xml");
 
        // Get the "HelloWorld" bean object
        // and call getName() method
        HelloWorld Geeks1
            = (HelloWorld)ap.getBean("hw");
 
        // Set the name
        Geeks1.setName("Geeks1");
        System.out.println(
            "Hello object (hello1)"
            + " Your name is: "
            + Geeks1.getName());
 
        // Get another "HelloWorld" bean object
        // and call getName() method
        HelloWorld Geeks2
            = (HelloWorld)ap.getBean("hw");
 
        System.out.println(
            "Hello object (hello2)"
            + " Your name is: "
            + Geeks2.getName());
 
        // Now compare the references to see
        // whether they are pointing to the
        // same object or different object
        System.out.println(
            "'Geeks1' and 'Geeks2'"
            + " are referring"
            + "to the same object: "
            + (Geeks1 == Geeks2));
 
        // Print the address of both
        // object Geeks1 and Geeks2
        System.out.println(
            "Address of object Geeks1: "
            + Geeks1);
        System.out.println(
            "Address of object Geeks2: "
            + Geeks2);
    }
}


Java
// Java program to illustrate a bean
// created in the spring framework
package bean;
 
public class HelloWorld {
    public String name;
 
    // Create a setter method to
    // set the value passed by user
    public void setName(String name)
    {
        this.name = name;
    }
 
    // Create a getter method so that
    // the user can get the set value
    public String getName()
    {
        return name;
    }
}


XML

 < beans>
      
     < bean
         id = "hw"
         class = "bean.HelloWorld"
         scope = "prototype" / >


Java
// Java program to illustrate
// the client to perform the
// request to the defined bean
 
package driver;
 
import org.springframework
    .context.ApplicationContext;
 
import org.springframework.context.support
    .ClassPathXmlApplicationContext;
 
import bean.HelloWorld;
 
public class Client {
 
    public static void main(String[] args)
    {
        // Load the Spring XML configuration
        // file into IoC container
        ApplicationContext ap
            = new ClassPathXmlApplicationContext(
                "resources/spring.xml");
 
        // Get the "HelloWorld" bean object
        // and call getName() method
        HelloWorld Geeks1
            = (HelloWorld)ap.getBean("hw");
 
        // Set the name
        Geeks1.setName("Geeks1");
 
        System.out.println(
            "Hello object (hello1)"
            + " Your name is: "
            + Geeks1.getName());
 
        // Get another "HelloWorld" bean object
        // and call getName() method
        HelloWorld Geeks2
            = (HelloWorld)ap.getBean("hw");
 
        System.out.println(
            "Hello object (hello2)"
            + "Your name is: "
            + Geeks2.getName());
 
        // Now compare the references to see
        // whether they are pointing to the
        // same object or different object
        System.out.println(
            "'Geeks1' and 'Geeks2'"
            + "are referring "
            + "to the same object: "
            + (Geeks1 == Geeks2));
 
        // Print the address of both
        // object Geeks1 and Geeks2
        System.out.println(
            "Address of object Geeks1: "
            + Geeks1);
        System.out.println(
            "Address of object Geeks2: "
            + Geeks2);
    }
}


  • 第 2 步:现在,我们编写一个 Spring XML 配置文件“spring.xml”并配置上面定义的 bean。

XML



     
     < bean
         id = "hw"
         class= "bean.HelloWorld"
         scope = "singleton" / >

  • 第三步:最后,编写一个驱动类“Client. Java”来请求上面的bean。

Java

// Java program to illustrate
// the client to perform the
// request to the defined bean
 
package driver;
 
import org.springframework
    .context.ApplicationContext;
 
import org.springframework
    .context.support
    .ClassPathXmlApplicationContext;
 
import bean.HelloWorld;
 
// Client Class to request the
// above defined bean
public class Client {
 
    public static void main(String[] args)
    {
        // Load the Spring XML configuration
        // file into IoC container
        ApplicationContext
            ap
            = new ClassPathXmlApplicationContext(
                "resources/spring.xml");
 
        // Get the "HelloWorld" bean object
        // and call getName() method
        HelloWorld Geeks1
            = (HelloWorld)ap.getBean("hw");
 
        // Set the name
        Geeks1.setName("Geeks1");
        System.out.println(
            "Hello object (hello1)"
            + " Your name is: "
            + Geeks1.getName());
 
        // Get another "HelloWorld" bean object
        // and call getName() method
        HelloWorld Geeks2
            = (HelloWorld)ap.getBean("hw");
 
        System.out.println(
            "Hello object (hello2)"
            + " Your name is: "
            + Geeks2.getName());
 
        // Now compare the references to see
        // whether they are pointing to the
        // same object or different object
        System.out.println(
            "'Geeks1' and 'Geeks2'"
            + " are referring"
            + "to the same object: "
            + (Geeks1 == Geeks2));
 
        // Print the address of both
        // object Geeks1 and Geeks2
        System.out.println(
            "Address of object Geeks1: "
            + Geeks1);
        System.out.println(
            "Address of object Geeks2: "
            + Geeks2);
    }
}
  • 输出:
Hello object (hello1) Your name is: Geeks1
Hello object (hello2) Your name is: Geeks1
'Geeks1' and 'Geeks2' are referring to the same object: true
Address of object Geeks1: bean.HelloWorld@627551fb
Address of object Geeks2: bean.HelloWorld@627551fb
  • 说明:当我们使用“Geeks1”和“Geeks2”的引用调用getName()方法时,我们得到相同的输出。这意味着两个引用都在调用同一个对象的 getName() 方法。此外,当我们比较引用“Geeks1”和“Geeks2”时,输出为“true”,这意味着在“Geeks1”和“Geeks2”之间共享同一个对象。所以很明显,当我们第一次发出请求时,会创建一个新的 bean 实例(HelloWorld),并且对于每个新请求,都共享同一个对象。

原型范围:

如果范围被声明为原型,那么每次对该特定 bean 发出请求时,spring IOC 容器都会创建该 bean 的一个新实例。可以使用getBean()方法以编程方式向 bean 实例发出请求,也可以通过 XML 进行次要类型的依赖注入。通常,我们对所有有状态的 bean 使用原型范围,而对无状态 bean 使用单例范围。
让我们通过一个例子来理解这个范围:

  • 第1步:让我们首先创建一个bean(即),它是spring框架中应用程序的主干。

Java

// Java program to illustrate a bean
// created in the spring framework
package bean;
 
public class HelloWorld {
    public String name;
 
    // Create a setter method to
    // set the value passed by user
    public void setName(String name)
    {
        this.name = name;
    }
 
    // Create a getter method so that
    // the user can get the set value
    public String getName()
    {
        return name;
    }
}
  • 第 2 步:现在,我们编写一个 Spring XML 配置文件“spring.xml”并配置上面定义的 bean。

XML


 < beans>
      
     < bean
         id = "hw"
         class = "bean.HelloWorld"
         scope = "prototype" / >

  • 第三步:最后,编写一个驱动类“Client. Java”来请求上面的bean。

Java

// Java program to illustrate
// the client to perform the
// request to the defined bean
 
package driver;
 
import org.springframework
    .context.ApplicationContext;
 
import org.springframework.context.support
    .ClassPathXmlApplicationContext;
 
import bean.HelloWorld;
 
public class Client {
 
    public static void main(String[] args)
    {
        // Load the Spring XML configuration
        // file into IoC container
        ApplicationContext ap
            = new ClassPathXmlApplicationContext(
                "resources/spring.xml");
 
        // Get the "HelloWorld" bean object
        // and call getName() method
        HelloWorld Geeks1
            = (HelloWorld)ap.getBean("hw");
 
        // Set the name
        Geeks1.setName("Geeks1");
 
        System.out.println(
            "Hello object (hello1)"
            + " Your name is: "
            + Geeks1.getName());
 
        // Get another "HelloWorld" bean object
        // and call getName() method
        HelloWorld Geeks2
            = (HelloWorld)ap.getBean("hw");
 
        System.out.println(
            "Hello object (hello2)"
            + "Your name is: "
            + Geeks2.getName());
 
        // Now compare the references to see
        // whether they are pointing to the
        // same object or different object
        System.out.println(
            "'Geeks1' and 'Geeks2'"
            + "are referring "
            + "to the same object: "
            + (Geeks1 == Geeks2));
 
        // Print the address of both
        // object Geeks1 and Geeks2
        System.out.println(
            "Address of object Geeks1: "
            + Geeks1);
        System.out.println(
            "Address of object Geeks2: "
            + Geeks2);
    }
}
  • 输出:
Hello object (hello1) Your name is: Geeks1
Hello object (hello2) Your name is: null
'Geeks1' and 'Geeks2' are referring to the same object: false
Address of object Geeks1: bean.HelloWorld@47ef968d
Address of object Geeks2: bean.HelloWorld@23e028a9
  • 说明:当我们使用引用“Geeks1”和“Geeks2”调用getName () 方法时,我们会得到不同的输出,这意味着两个引用都在调用不同对象的 getName() 方法。此外,当我们比较引用“Geeks1”和“Geeks2”时,输出为“false”,这意味着两个引用都指向不同的对象。因此很明显,在对该 bean 发出的每个请求时都会创建一个新的 bean 实例 (HelloWorld)。
    单例和原型之间的区别
SingletonPrototype
Only one instance is created for a single bean definition per Spring IoC containerA new instance is created for a single bean definition every time a request is made for that bean.
Same object is shared for each request made for that bean. i.e. The same object is returned each time it is injected.For each new request a new instance is created. i.e. A new object is created each time it is injected.
By default scope of a bean is singleton. So we don’t need to declare a been as singleton explicitly.By default scope is not prototype so you have to declare the scope of a been as prototype explicitly.
Singleton scope should be used for stateless beans.While prototype scope is used for all beans that are stateful