單例範圍

如果使用 singleton 範圍定義 bean,則只會在 Spring 容器中初始化一個物件例項。對此 bean 的所有請求都將返回相同的共享例項。這是定義 bean 時的預設範圍。

給出以下 MyBean 類:

public class MyBean {
    private static final Logger LOGGER = LoggerFactory.getLogger(MyBean.class);
    private String property;

    public MyBean(String property) {
        this.property = property;
        LOGGER.info("Initializing {} bean...", property);
    }

    public String getProperty() {
        return this.property;
    }

    public void setProperty(String property) {
        this.property = property;
    }
}

我們可以用 @Bean 註釋定義一個單例 bean:

@Configuration
public class SingletonConfiguration {

    @Bean
    public MyBean singletonBean() {
        return new MyBean("singleton");
    } 
}

以下示例從 Spring 上下文中檢索兩次相同的 bean:

MyBean singletonBean1 = context.getBean("singletonBean", MyBean.class);
singletonBean1.setProperty("changed property");

MyBean singletonBean2 = context.getBean("singletonBean", MyBean.class);

記錄 singletonBean2 屬性時,將顯示訊息 changed property ,因為我們只檢索了相同的共享例項。

由於例項是在不同元件之間共享的,因此建議為無狀態物件定義單例範圍。

懶惰的單例豆

預設情況下,單例 bean 是預先例項化的。因此,將在建立 Spring 容器時建立共享物件例項。如果我們啟動應用程式,將顯示 “正在初始化單例 bean …” 訊息。

如果我們不希望預先例項化 bean,我們可以將 @Lazy 註釋新增到 bean 定義中。這將阻止在第一次請求 bean 之前建立 bean。

@Bean
@Lazy
public MyBean lazySingletonBean() {
    return new MyBean("lazy singleton");
}

現在,如果我們啟動 Spring 容器,則不會出現 “正在初始化 lazy singleton bean …” 訊息。在第一次請求 bean 之前,不會建立 bean:

logger.info("Retrieving lazy singleton bean...");
context.getBean("lazySingletonBean");

如果我們執行應用程式同時定義了 singleton 和 lazy singleton bean,它將產生以下訊息:

Initializing singleton bean...
Retrieving lazy singleton bean...
Initializing lazy singleton bean...