不要想得太复杂,scope=request/session,说白了就一句话:“IOC容器创建一个bean,然后把这个bean放在request域或session域”,就这么多,没了。
不管这个bean是放进去也好还是取出来也好,核心问题就出来了:
1. “什么时候拿到request?”
2. “如何拿到正确的request?”
从server的角度而言,ServletRequestListener侦听request的创建和销毁,同时request是和线程绑定的,所以通过线程可以拿到request,所以,解决方案就出来了:
1. 什么时候拿?创建request的时候拿,通过ServletRequestListener侦听request的创建和销毁,然后放入Thread Local中;
2. 怎么拿到正确的request?通过ThreadLocal保证,将request对象放入Thread.ThreadLocal.ThreadLocalMap中,每个线程带着自己的request走;
Spring给出的解决方案:RequestContextListener实现了ServletRequestListener,RequestContextHolder封装了ThreadLocal,AbstractBeanFactory的getBean方法中通过Scope转到RequestContextHolder,再转到ThreadLocal拿到request,创建出来的bean要存要取予取予求。
一、容器
1. 容器
抛出一个议点:BeanFactory是IOC容器,而ApplicationContex则是Spring容器。
什么是容器?Collection和Container这两个单词都有存放什么东西的意思,但是放在程序猿的世界,却注定是千差万别。Collection,集合,存放obj instanceof Class为true的一类对象,重点在于存放;Container,容器,可以存放各种各样的obj,但不仅仅是存放,他被称为容器,更重要的是他能管理存放对象的生命周期和依赖。
容器:用于存放对象,并能对存放对象进行生命周期管理和依赖管理。
2. Spring IOC容器是BeanFactory
Spring IOC容器是BeanFactory,也正是基于【容器】的论点。
在逻辑和源码分析之前,先做一些铺垫。对于使用Spring的程序猿来说,常用是ApplicationContext接口及其实现子类,ClasPathXmlApplicationContext、FileSystemXmlApplicationContext、XmlWebApplicationContext和AnnotationConfigWebApplicationContext,对于这四个类来说,他们都有一个共同的抽象父类AbstractRefreshableApplicationContext,而正是在该抽象父类中完成对BeanFactory的装饰。
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
private Boolean allowBeanDefinitionOverriding;
private Boolean allowCircularReferences;
/** Bean factory for this context */
private DefaultListableBeanFactory beanFactory;
所有通过ApplicationContext接入使用Spring服务的,都是使用该bean工厂,而且最重要的是这个bean工厂实现了所有BeanFactory的接口、抽象类,拥有完整的Spring IOC逻辑。