1. Spring的Scope(作用域)有5种,分别是:
1) singleton(单例模式): 全局有且仅有一个实例
2) prototype(原型模式/多态模式): 每次获取Bean的时候会有一个新的实例
3) request: 针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效
4) session: 针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效
5) global session: 类似于标准的session作用域,不过它仅仅在基于portlet的web应用中才有意义
2. Singleton:
The singleton scope Only one shared instance of a singleton bean is managed, and all requests for beans with an id or ids matching that bean definition result in that one specific bean instance being returned by the spring Container.
To put it another way, when you define a bean definition and it is scoped as a singleton, the Spring IoC container creates exactly one instance of the object defined by that bean definition. This single instance is stored in a cache of such singleton beans, and all subsequent requests and references for that named bean return the cached object.
当声明一个对象的scope="singleton"时,spring 容器将会通过Ioc方式生成仅此一个accoutDao对象并保存在内存中。
当用户调用ApplicationContext.getBean("accoutDao")时返回该对象。说白了和单例是一样的道理,只不过持有该对象引用的是spring容器,所以不需要我们去担心它的生命周期。
3.Prototype:
The non-singleton, prototype scope of bean deployment results in the creation of a new bean instance every time a request for that specific bean is made. That is, the bean is injected into another bean or you request it through a getBean() method call on the container. As a rule, use the prototype scope for all stateful beans and the singleton scope for stateless beans.
The following diagram illustrates the Spring prototype scope. A data access object (DAO) is not typically configured as a prototype, because a typical DAO does not hold any conversational state; it was just easier for this author to reuse the core of the singleton diagram.
每次用户调用(ApplicationContext.getBean("accoutDao"))Spring都创建一个accoutDao对象。
4.该使用singleton 还是 prototype?
取决于你所注入的对象是否包含状态。
比较适合用Singleton单例模式的就是dao/service,因为他们不包含变化的成员变量,方法调用不会改变这个对象的状态(它也没有状态可言),如下面这个类只有一个成员变量sessionFactory,而该变量是由spring注入的,全局也只有一个,可以看成是BaseDaoImpl的一个静态变量,不存在状态变化。因此下面的类比较适合用singleton。
@Repository("baseDao")
public class BaseDaoImpl<T> implements BaseDaoI<T> {
private SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
@Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Serializable save(T o) {
return sessionFactory.getCurrentSession().save(o);
}
public void delete(T o) {
sessionFactory.getCurrentSession().delete(o);
}
public void update(T o) {
sessionFactory.getCurrentSession().update(o);
}
public void saveOrUpdate(T o) {
sessionFactory.getCurrentSession().saveOrUpdate(o);
}
}
5.SpringMVC线程安全问题:
1) 对于spring的IOC来说,对象是由Spring来帮我们管理,也就是在Spring启动的时候,在Spring容器中,由Spring给我们创建的,Spring会帮我们维护,一般都是单例的,也就是一个对象。
2) spring生成对象默认是单例的。通过scope属性可以更改为多例。
3) 验证Spring生成对象默认是单例的
<bean id="singleton" class="java.util.Date" scope="singleton"></bean>
<bean id="prototype" class="java.util.Date" scope="prototype"></bean>
package test;
import java.util.Date;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.opensymphony.xwork2.ActionContext;
public class TestScope {
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext-web.xml");
Date s1=(Date)context.getBean("singleton");
Date p1=(Date)context.getBean("prototype");
Date s2=(Date)context.getBean("singleton");
Date p2=(Date)context.getBean("prototype");
System.out.println("单例:"+(s1==s2));
System.out.println("单例:"+(p1==p2));
}
}
输出结果
单例:true
单例:false
4) SpringMVC是基于方法的拦截,而Struts2是基于类的拦截。
5) 对于Struts2来说,因为每次处理一个请求,struts就会实例化一个对象,这样就不会有线程安全的问题。
6) Spring的controller默认是Singleton的,这意味着每一个request过来,系统都会用原有的instance去处理。好处: 一是我们不用每次创建Controller,二是减少了对象创建和垃圾收集的时间。由于只有一个Controller的instance,当多个线程调用它的时候,它里面的instance变量就不是线程安全的了,会发生窜数据的问题。因此,我们在使用SpringMVC的contrller时,应避免在controller中定义实例变量。
public class Controller extends AbstractCommandController {
protected Company company;
protected ModelAndView handle(HttpServletRequest request,HttpServletResponse response,Object command,BindException errors) throws Exception {
company = ................;
}
}
7) 如果要在Controller中定义实例变量,有几种解决方法:
a) 在Controller中使用ThreadLocal变量
b) 在spring配置文件Controller中声明 scope="prototype",每次都创建新的controller
@Controller
@RequestMapping("/fui")
public class FuiController extends SpringController {
//这么定义的话就是单例
@Controller
@Scope("prototype")
@RequestMapping("/fui")
public class FuiController extends SpringController {
//每次都创建