由于看淘淘商城的项目,涉及到了项目中处理spring中bean对象的两种类型,分别是单例和多例,就在此记录一下,方便加深理解,写出更加健壮的代码。
一、单例和多例的概述
在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 }