0、什么是对象作用域
① Spring中可以定义有状态的Bean对象作用域为singleton
② 有状态会话bean:每个用户私有一个实例,在用户的生存期内,bean保持了用户的信息,即“有状态”;一旦用户灭亡(调用结束或实例结束),bean的生命期也告结束。即每个用户最初都会得到一个初始的bean。
③ Spring中可以定义无状态的Bean对象作用域为prototype
④ 无状态会话bean:bean一旦实例化就被加进会话池中,各个用户都可以共用。即使用户已经消亡,bean的生命期也不一定结束,它可能依然存在于会话池中,供其他用户调用。由于没有特定的用户,那么也就不能保持某一用户的状态,所以叫无状态bean。但无状态会话bean 并非没有状态,如果它有自己的属性(变量),那么这些变量就会受到所有调用它的用户的影响,这是在实际应用中必须注意的。
1、什么是FactoryBean
① FactoryBean是接口,其在IOC容器的基础上给实例化Bean对象添加了简单工厂模式和装饰器模式,用户可以在getObject方法中自定义实例化Bean,为IOC容器中复杂Bean的实例化提供了更加灵活的方式
② 一般情况下,Spring通过反射机制利用<bean>的class属性指定实例化Bean,但某些情况下,实例化Bean的过程比较复杂,如果按照原始方式,需要在<bean>中提供大量的配置信息,不够灵活,这时采用编码方式更简单,因此Spring提供了FactoryBean的工厂类接口,用户可以通过实现该接口,自定义实例化Bean的逻辑
③ 当spring.xml的<bean>的class配置的是FactoryBean的实现类时,通过getBean()方法返回的不是FactoryBean本身,而是FactoryBean#getObject()方法所返回的对象,相当于FactoryBean#getObject()得到的Bean对象,替代了createBean()所得到的Bean对象
④ 如果bean实例不是FactoryBean类型,则直接返回bean实例;如果bean实例是FactoryBean类型,而beanName又是以&开头【beanFactory.getBean("&user")】,直接返回bean实例;如果bean实例是FactoryBean类型,而beanName不是以&开头,则返回bean实例的getObject()方法获取的对象实例(一般getObject()方法中就是我们需要的实例对象的创建过程)
2、为什么要对象作用域和BeanFactory
① 实际业务中不仅需要单例Bean对象,也需要原型模式的Bean对象
② 因此本章增加了对Bean对象作用域的定义、管理
③ 交由Spring管理的Bean对象,不一定都是由类创建出来的
④ 本章就是要把复杂且以代理方式动态变化的bean对象,注入Spring容器
⑤ 对外提供一个可以二次从 FactoryBean 的 getObject方法中获取对象的功能即可
3、项目部分源码分析
① +FactoryBean<T>:接口中定义getObject方法,实现了该方法的类,可以自定义对象功能
② +IUserDao:测试使用,定义了一个查询接口
③ +ProxyBeanFactory:测试使用,实现FactoryBean中的getObject,模拟了 UserDao 的原有功能,类似于 MyBatis 框架中的代理操作
④ BeanDefinition:新增scope属性,默认为singleton,定义布尔类型的singleton、prototype,解析spring.xml中的scope标签值如果是singleton,则属性singleton=true,prototype=false
⑤ XmlBeanDefinitionReader:读取spring.xml中的scope属性注入beanDefinition
⑥ AbstractAutowireCapableBeanFactory:创建Bean对象初始化结束后,根据beanDefinition中的singleton属性判断是否要将Bean对象存入单例Bean对象容器;创建Bean对象时,也无需将非singleton类型的Bean对象注入disposableBeans容器,因为Singleton对象由Spring容器销毁,Prototype对象由JVM销毁
⑦ DefaultSingletonBeanRegistry:定义了一个NULL_OBJECT
⑧ +FactoryBeanRegistrySupport:定义factoryBeanObjectCache用来存放单例类型的对象,避免重复创建,对外提供获取容器对象的方法。取Bean对象分两种情况, 1)如果实现了FactoryBean接口的Bean对象是单例的,则从factoryBeanObjectCache单例缓存池中取,如果缓存池中没有,则调用getObject方法创建对象,并会在缓存中也保存一下,以备下次使用 2)如果Bean不是单例对象,则直接调用getObject方法创建新对象
⑨ AbstractBeanFactory:doGetBean方法的逻辑有较大调整,先从单例Bean对象容器中取Bean对象,如果取不到,则创建Bean对象,然后判断Bean对象是否是FactoryBean的实例或子类实例,如果不是,直接给用户返回Bean对象;如果是,则调用FactoryBeanRegistrySupport类中的方法,即获取单例Bean对象或创建新的Bean对象
4、类关系图
5、调用逻辑图
6、参考
https://www.cnblogs.com/aspirant/p/9082858.html#https://www.cnblogs.com/aspirant/p/9082858.html#https://www.cnblogs.com/youzhibing/p/10528821.html#
https://www.cnblogs.com/youzhibing/p/10528821.html#第10章:对象作用域和FactoryBean | bugstack 虫洞栈包含: Java 基础,面经手册,Netty4.x,手写Spring,用Java实现JVM,重学Java设计模式,SpringBoot中间件开发,IDEA插件开发,DDD系统架构项目开发,字节码编程...
https://bugstack.cn/md/spring/develop-spring/2021-06-30-%E7%AC%AC10%E7%AB%A0%EF%BC%9A%E6%A8%AA%E5%88%80%E8%B7%83%E9%A9%AC%EF%BC%8C%E5%85%B3%E4%BA%8EBean%E5%AF%B9%E8%B1%A1%E4%BD%9C%E7%94%A8%E5%9F%9F%E4%BB%A5%E5%8F%8AFactoryBean%E7%9A%84%E5%AE%9E%E7%8E%B0%E5%92%8C%E4%BD%BF%E7%94%A8.html