- singleton 作用域:表示在 Spring 容器中只有一个 Bean 实例,以单例的形式存在,是默认的 Bean 作用域。
- prototype 作用域:原型作用域,每次调用 Bean 时都会创建一个新实例,也就是说每次调用 getBean() 方法时,相当于执行了 new Bean()。
- request 作用域:每次 Http 请求时都会创建一个新的 Bean,该作用域仅适应于 WebApplicationContext 环境。
- session 作用域:同一个 Http Session 共享一个 Bean 对象,不同的 Session 拥有不同的 Bean 对象,仅适用于 WebApplicationContext 环境。
- application 作用域:全局的 Web 作用域,类似于 Servlet 中的 Application。
大部分时候我们并没有在系统中使用多线程,所以很少有人会关注这个问题。单例 bean 存在线程问题,主要是因为当多个线程操作同一个对象的时候,对这个对象的非静态成员变量的写操作会存在线程安全问题。
常见的有两种解决办法:
- 在Bean对象中尽量避免定义可变的成员变量(不太现实)。
- 在类中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在 ThreadLocal 中(推荐的一种方式)。
- 第一级缓存:单例缓存池singletonObjects。
- 第二级缓存:早期提前暴露的对象缓存earlySingletonObjects。(属性还没有值对象也没有被初始化)
- 第三级缓存:singletonFactories单例对象工厂缓存。
- 首先finishBeanFactoryInitialization->preInstantiateSingletons->getBean->doGetBean;
- 在doGetBean中,transformedBeanName:主要负责判断一下有木有别名;getSingleton:从一级缓存singletonObjects拿bean,在getSingleton方法中,有一个判断条件就是isSingletonCurrentlyInCreation,判断为false,因为他是第一次进来,并且还没有正在创建该bean;dependsOn:依赖,暂时先不说他。
- 再来一次getSingleton:再一次的从singketonObjects缓存拿,依然没有的。接着有个重点beforeSingletonCreation:它把bean添加到临时的singletonsCurrentlyInCreation,这就意味着,下次再碰见它,那可就是true了。接着singletonFactory.getObject(),这里getObject调用的是传递的接口createBean方法。
- 在createBean方法中:有个doCreateBean->createBeanInstance方法:它就是直接实例化,实际上构造器有反应了(区分JVM创建对象和Spring创建对象),但是没有赋值(初始化);earlySingletonExposure:提前暴漏该bean。但要知道三个变量,为什么他是true:isSingleton(),是否单例,那肯定是哦;(这里解释了这里是单例才能提前曝漏,意味着才能存三级缓存)allowCircularReferences,默认变量为true,写死了;isSingletonCurrentlyInCreation,这里可就为true了,因为步骤3,已经将它设置为true了。那么会进来这个方法:addSingletonFactory
- addSingletonFactory在这个方法中:将该bean放入到三级缓存singletonFactories中。(解决循环依赖)
- 接下来,就是它了,populateBean:实际上就是属性赋值。(如果这里要有A依赖B,又发现三级缓存中没有B,那么它就会再次执行一次(递归开始)getBean->doGetBean->createBeanInstance(把B给实例化一下),同样的道理,这里会将B也会放入三级缓存中,B开始populateBean,那么它发现B依赖A,此时三级缓存中有A(精髓,牛逼),然后把A放到二级缓存中,同时从三级缓存中移除,接着得到A之后直接赋值,最后完成了初始化,然后来到addSingleton,将B仍到了一级缓存,同时将B从三级缓存仍出去)返回B,递归结束,得到B之后将B的赋值给A了。
- 最后将二级缓存的A删除,仍到一级缓存中。
- Bean 容器找到配置文件中 Spring Bean 的定义。
- Bean 容器利用 Java Reflection API 创建一个Bean的实例。
- 如果涉及到一些属性值 利用
set()方法设置一些属性值。 - 如果 Bean 实现了
BeanNameAware接口,调用setBeanName()方法,传入Bean的名字。 - 如果 Bean 实现了
BeanClassLoaderAware接口,调用setBeanClassLoader()方法,传入ClassLoader对象的实例。 - 与上面的类似,如果实现了其他
*.Aware接口,就调用相应的方法。 - 如果有和加载这个 Bean 的 Spring 容器相关的
BeanPostProcessor对象,执行postProcessBeforeInitialization()方法 - 如果Bean实现了
InitializingBean接口,执行afterPropertiesSet()方法。 - 如果 Bean 在配置文件中的定义包含 init-method 属性,执行指定的方法。
- 如果有和加载这个 Bean的 Spring 容器相关的
BeanPostProcessor对象,执行postProcessAfterInitialization()方法 - 当要销毁 Bean 的时候,如果 Bean 实现了
DisposableBean接口,执行destroy()方法。 - 当要销毁 Bean 的时候,如果 Bean 在配置文件中的定义包含 destroy-method 属性,执行指定的方法。
