一、單例和多例的概述
在Spring中,bean可以被定義為兩種模式:prototype(多例)和singleton(單例)。所謂單例,就是所有的請求都由一個對象來進行處理,比如我們常用的service和dao層的對象通常都是單例的,而多例則指每個請求用一個新的對象來處理。
singleton(單例):只有一個共享的實例存在,所有對這個bean的請求都會返回這個唯一的實例。不管new多少次,只生成一個對象。
prototype(多例):對這個bean的每次請求都會創建一個新的bean實例,類似於new。
二、為什么使用單例或多例
之所以用單例,是因為沒必要每個請求都新建一個對象,這樣子既浪費CPU又浪費內存;之所以用多例,是為了防止並發問題;即一個請求改變了對象的狀態,此時對象又處理另一個請求,而之前請求對對象狀態的改變導致了對象對另一個請求做了錯誤的處理。
用單例和多例的標准只有一個:當對象含有可改變的狀態時(更精確的說就是在實際應用中該狀態會改變),則多例,否則單例。就如dao和service這兩層的數據一般不會有相應的屬性修改,所以可以考慮用單例,而Controller層會存儲很多需要操作的vo類(value object值對象),此時這個對象的狀態就會被改變,就要使用多例。
三、如何使用多例
這里是指定的特定場景下,就是記錄一下,其中涉及到的一小點,先說一下,在什么情況下使用的這個spring中的bean的多例模式,就是項目中前台web項目需要使用HttpClient連接訪問后台的接口地址,在使用HttpClient的過程中,涉及到連接的各種配置以及HttpClient連接池的使用,我們把一些公用的配置以及連接池,HttpClient構造器等一些配置,配置到單獨的配置文件中,spring容器自己創建、管理這些對象,我們只需要注入這些對象就可以使用了,是不是很方便。這也是優化代碼的一種方式,抽取出公共的部分,交由spring管理,這其中涉及到了RequestConfig(請求HttpClient連接的配置文件,這個是單例的)、CloseableHttpClient(HttpClient連接對象,這個要設計成多例的,在調用同一個方法時會創建不同的HttpClient對象)
注意:多例對象在使用的時候是不可以用注入的方式的@Autowired
具體解決辦法是:實現BeanFactoryAware接口,重寫setBeanFactory()方法,在spring容器初始化時傳入BeanFactory,通過BeanFactory創建HttpClient連接對象
1 package com.taotao.web.service; 2 3 import java.io.IOException; 4 import java.net.URISyntaxException; 5 import java.util.ArrayList; 6 import java.util.List; 7 import java.util.Map; 8 9 import org.apache.http.NameValuePair; 10 import org.apache.http.client.ClientProtocolException; 11 import org.apache.http.client.config.RequestConfig; 12 import org.apache.http.client.entity.UrlEncodedFormEntity; 13 import org.apache.http.client.methods.CloseableHttpResponse; 14 import org.apache.http.client.methods.HttpGet; 15 import org.apache.http.client.methods.HttpPost; 16 import org.apache.http.client.utils.URIBuilder; 17 import org.apache.http.impl.client.CloseableHttpClient; 18 import org.apache.http.message.BasicNameValuePair; 19 import org.apache.http.util.EntityUtils; 20 import org.springframework.beans.BeansException; 21 import org.springframework.beans.factory.BeanFactory; 22 import org.springframework.beans.factory.BeanFactoryAware; 23 import org.springframework.beans.factory.annotation.Autowired; 24 import org.springframework.stereotype.Service; 25 26 import com.taotao.web.httpclient.HttpResult; 27 28 @Service 29 public class ApiService implements BeanFactoryAware{ 30 31 @Autowired 32 private RequestConfig requestConfig; 33 34 private BeanFactory beanFactory; 35 36 private CloseableHttpClient getHttpClient(){ 37 return this.beanFactory.getBean(CloseableHttpClient.class); 38 } 39 40 @Override 41 public void setBeanFactory(BeanFactory beanFactory) throws BeansException { 42 //該方法是在spring容器初始化時調用,傳入beanFactory 43 this.beanFactory = beanFactory; 44 } 45 }