Java如何在Spring中定义bean作用域?

Bean作用域定义是如何创建Bean并将其从Spring容器返回给Bean请求者的。默认情况下,所有bean的范围都是单例。每当需要该bean时,例如在注入或使用getBean()应用程序上下文中的方法进行调用时,spring容器将始终返回相同的bean 。

Spring容器中定义了五种类型的bean作用域:

范围描述
singleton每个Spring容器将Bean定义范围限制为单个Bean实例。当创建bean时未定义范围时,这是默认范围。
prototype对bean进行范围调整,以允许多次创建bean。每次需要bean时都会创建一个新bean。
request将bean定义的作用域限定为单个HTTP请求。*
session将bean定义的作用域限定为单个HTTP会话。*
global-session将bean定义的作用域限定为全局HTTP会话。*

*)仅在使用支持Web的Spring上下文时有效。

让我们看看Singleton和Prototype作用域之间的区别。首先,我们将创建我们的DummyService课程。

package org.nhooo.example.spring.dummy;

public class DummyService {
    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

单例范围

默认情况下,如果未定义任何范围,它将是单例。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="service"/>

</beans>

现在创建一个程序来运行我们的示例。首先将使用singleton.xml作为配置运行它。

package org.nhooo.example.spring.dummy;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanScopeDemo {
    public static void main(String[] args) {
        ApplicationContext context =
            new ClassPathXmlApplicationContext("singleton.xml");

        DummyService serviceA =
            (DummyService) context.getBean("service");
        serviceA.setMessage("Hello From A");
        System.out.println("Message A = " + serviceA.getMessage());

        DummyService serviceB =
            (DummyService) context.getBean("service");
        System.out.println("Message B = " + serviceB.getMessage());
    }
}

单例配置的输出为:

Message A = Hello From A
Message B = Hello From A

上面的输出显示所打印的消息serviceB与相同serviceA。我们甚至没有在serviceB显式设置消息。它输出相同的消息,因为该getBean()方法实际上为serviceA和返回相同的bean serviceB。这是单例范围。

原型范围

要将范围更改为原型,请使用scopebean元素中的属性,如下所示。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="service"
          scope="prototype"/>

</beans>
package org.nhooo.example.spring.dummy;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanScopePrototypeDemo {
    public static void main(String[] args) {
        ApplicationContext context =
            new ClassPathXmlApplicationContext("prototype.xml");

        DummyService serviceA =
            (DummyService) context.getBean("service");
        serviceA.setMessage("Hello From A");
        System.out.println("Message A = " + serviceA.getMessage());

        DummyService serviceB =
            (DummyService) context.getBean("service");
        System.out.println("Message B = " + serviceB.getMessage());
    }
}

现在,如果您尝试再次运行同一程序,但将配置更改prototype.xml为以下内容,则会得到以下输出:

Message A = Hello From A
Message B = null

在serviceB现在打印不同的消息。这是使用prototype示波器的效果。当我们调用时,getBean()将根据请求创建一个新bean。