2、Spring IOC

1、Sring IOC控制反转:将对象的创建、依赖关系注入(装配)、销毁等整个生命周期的操作全部交给IOC容器管理,脱离代码实现解耦Spring容器中是一切皆BeanBeanFactory与ApplicationContext一般称BeanFactory为IoC容器,而称ApplicationContext为应用上下文,都可以当做spring容器BeanFactory:Spr...
摘要由CSDN通过智能技术生成

1、Sring IOC
控制反转:将对象的创建、依赖关系注入(装配)、销毁等整个生命周期的操作全部交给IOC容器管理,脱离代码实现解耦
在这里插入图片描述
Spring容器中是一切皆Bean

BeanFactory与ApplicationContext
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
一般称BeanFactory为IoC容器,而称ApplicationContext为应用上下文,都可以当做spring容器

BeanFactory:
Spring容器最基本的接口就是BeanFactory。BeanFactory负责基本的创建、配置、管理Bean,同时还管理着Bean和Bean之间的依赖关系。它的一个默认实现DefaultListableBeanFactory正是spring容器初始化时需要用到的。

ApplicationContext:
ApplicationContext是BeanFactory的子接口,提供更多的企业级服务,如:
1、加载bean配置信息(AnnotationConfigApplicationContext、ClassPathXmlApplicationContext、FileSystemXmlApplicationContext、XmlWebApplicationContext)
装配bean三种方式:

  1. xml显示配置
  2. java类显示配置,
  3. 隐式的bean发现机制和自动装配(组件扫描(component scanning)、自动装配 (autowiring))

2、国际化,利用MessageSource
3、统一的资源访问,访问url和文件,利用ResourceLoader
4、实现ApplicationEventPublish的事件机制

2、依赖注入DI的方式

  1. 基于构造函数<constructor-arg>
  2. 基于setter方法<property>或p:命名空间
  3. 基于工厂方法
    非静态方法
    <bean id=“book11” factory-bean=“bookFactory” factory-method=“create”/>
    静态方法
    <bean id=“book12” class=“net.spring4.bean.BookFactory” factory-method=“createBook”/>

自动装配
1、xml方式
<bean autowire=””>,自动装配存在不确定性,尽量不要用
自动装配方式:
no: 不启用自动装配
byName: 和属性相同名字
byType: 使用相同类型
constructor: 把与Bean的构造器入参具有相同类型的其他Bean自动装配到Bean构造 器的对应入参中

全局自动装配:
默认情况下,default-autowire属性被设置为none,标识所有的Bean都不使用自动装配,除非Bean上配置了autowire属性。
<beans default-autowire=“none”>

2、注解方式
@Autowired和@Resource
@Autowired:
默认是按照byType来自动装配的,如果有多个类型匹配再按照byName(可以通过使用@qulifier指定匹配的名字)。
如果还是有多个实例满足,有两种解决方式:
1、使用@Primary,只能在一个bean上添加@Primary;
2、使用@Priority,设置优先级,可以在多个bean上添加,但不能存在优先级相同的bean;

@Resource:
按照byName来自动装配

3、循环依赖问题
bean之间互相引用,如A依赖B,B依赖A

spring中循环依赖有三种情况:
1、构造器注入形成的循环依赖:也就是beanB需要在beanA的构造函数中完成初始化,beanA也需要在beanB的构造函数中完成初始化,这种情况的结果就是两个bean都不能完成初始化,循环依赖难以解决。

2、setter注入构成的循环依赖:beanA需要在beanB的setter方法中完成初始化,beanB也需要在beanA的setter方法中完成初始化,spring设计的机制主要就是解决这种循环依赖,也是今天下文讨论的重点。

3、prototype作用域bean的循环依赖。这种循环依赖同样无法解决,因为spring不会缓存prototype作用域的bean,而spring中循环依赖的解决正是通过缓存来实现的。

下面主要说明第二种情况中循环依赖的解决方案
步骤一:
beanA进行实例化,并且将自己进行实例化的状态记录下来,并提前向外暴露一个单例工厂方法,从而使其他bean能引用到该bean
步骤二:
beanA中有beanB的依赖,于是开始实例化beanB。
步骤三:
实例化beanB的过程中又发现beanB依赖了beanA,于是又进行beanA的实例化,这时发现beanA已经在进行实例化了,程序发现了存在的循环依赖,然后通过步骤一中暴露的单例工程方法拿到beanA的引用(注意,此时的beanA只是完成了构造函数的注入但未完成其他步骤),从而beanB拿到beanA的引用,完成注入,完成了初始化,如此beanB的引用也就可以被beanA拿到,从而beanA也就完成了初始化。

spring进行bean的加载的时候,首先进行bean的实例化(调用构造函数),然后进行属性填充。在这两步中间,spring对bean进行了一次状态的记录,也就是说spring会把指向只完成了构造函数实例化的bean的引用通过一个变量记录下来,明白这一点对之后的源码理解至关重要。

源码中一些缓存说明:
/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects =
new ConcurrentHashMap<String, Object>(256);

/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories =
new HashMap<String, ObjectFactory<?>>(16);

/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects =
new HashMap<String, Object>(16);

singletonObjects:存放完全初始化好的 bean,从该缓存中取出的 bean 可以直接使用
earlySingletonObjects:存放原始的 bean 对象(尚未填充属性),用于解决循环依赖
singletonFactories:存放 bean 工厂对象,用于解决循环依赖

注意:
1、从设计上就应该避免循环依赖的情况;
2、spring aop中singletonObjects和earlySingletonObjects不是同一个bean,earlySingletonObjects保存了targetClass的原生bean,而singletonObjects保存了targetClass的动态代理bean,此时可以使用@Lazy懒加载。

源码分析可以参考【3、Spring AOP】

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值