Sping IOC 学习笔记
IOC 容器
org.springframework.beans 和 org.springframework.context包是spring IOC容器的基础。
BeanFactory 和 ApplicationContext:BeanFactory提供的高级配置机制,使得管理各种对象成为可能。而ApplicationContext是BeanFactory的扩展,功能进一步增强。简单而言,BeanFactory 提供了
配置框架以及基本功能,而ApplicationContext则增加了支持企业核心内容的功能,如事物处理和AOP、国际化等。ApplicationContext完全由BeanFactory扩展而来,因而具备BeanFactory的所有功能。
容器和bean
在spring中,那些组成应用程序的主体以及由Spring ICO容器所管理的对象,称为bean。bean的定义和bean之间的依赖关系则通过配置元数据来描述。
Spring IOC 容器的实际代表者和核心接口: BeanFactory, 它的职责包括:实例化、定位、配置应用程序中的对象以及建立这些对象间的依赖。
最常用的BeanFactory的实现:XmlBeanFactory.
Spring IOC 容器读取配置元数据,并通过它对应用中各个对象进行实例化、配置以及组装。
配置元数据的格式:基于xml和基于注解
Spring IOC 容器实例化:
createInstance()必须是一个static方法。
3、实例工厂方法实例化;
用来实例化的非静态实例工厂方法位于另外一个bean中,容器将调用该bean的工厂方法来创建一个新的bean实例。class属性必须为空,factory-bean指定为当前容器中包含的工厂方法的bean的名称,factory-method指向工厂bean中的工厂方法。
依赖注入
依赖注入背后的原理是对象之间的依赖关系。
两种方式:构造器注入和setter注入
构造器注入:通过调用带参数的构造器实现
构造器参数索引
注意,index是从0开始的。
setter方法注入:
Lookup方法注入:
此方法注入是用于依赖bean和协作bean的作用域不同的情况,比如一个singleton bean需要引用一个prototype bean。
bean依赖关系处理:
一、根据定义bean的配置文件创建并初始化BeanFacotry实例;
二、当这些bean被实际创建时,他相关的依赖也将提供给该bean;
三、每个属性或构造器参数既可以是一个实际的值,也可以是对容器中另外一个bean的引用。
四。每个指定的属性或者构造器参数值必须能够被转换成特定格式或者构造器参数所需的类型
在默认情况下,ApplicationContext实现中的bean采用的是提前实例化的singleton模式,这样做将带来时间和内存的开销,但是好处是ApplicationContext被加载的时候可以尽早的发现一些配置问题。不过用户也可以根据
需要采用延迟实例化的方式。
循环依赖:当一个类A,需要通过构造器注入类B,而类B又需要通过构造器注入类A,这样spring ioc容器将检测出循环引用,并抛出BeanCurrentlyInCreationException异常。
静态工厂方法注入:
只是传了bean的id值,并不是bean的引用,这里等同于:
引用其他bean
ref元素
<ref bean="someBean" />
引用同一容器或者父容器中的任何bean,无论是否在同一个xml配置文件中。bean的值既可以是bean的id值,也可以是name的值。
<ref local="someBean" />
如果所引用的bean在同一个xml配置文件中,可以用这种方式,但是local的属性值必须是目标bean的id值。
<ref parent="someBean" />
如果引用的目标bean在父容器中,可以使用此方式,parent属性值既可以是目标bean的id值,也可以是name属性值,而起目标bean必须在当前容器的父容器中。
内部bean
指在一个bean的<property />或 <constructor-arg />元素中使用<bean/>元素定义的bean。内部bean定义不需要id和name属性,即使指定也会被容器忽略。。
内部bean总是匿名的且他们总是prototype模式的,同时将内部bean注入到包含该内部bean之外的bean是不可能的
集合的合并:
从2.0开始,Spring IOC容器将支持集合的合并
此实例中,child bean的adminEmails属性的<props/>元素使用了merge=true属性,当child bean被容器实际解析以及实例化时,其adminEmails将与父集合的adminEmails属性进行合并.
合并功能仅在spring 2.0以及后版本中可用,不同的集合类型是不能合并的,比如Map类型的不能和list合并。
<null />元素
此元素用于处理null值,Spring会把属性的空参数当做空字符串处理;
如果要表达多个bean的依赖,可以再'depends-on'中指定多个bean名字,用逗号、空格、分号等隔开。
它同时也可以用来指定相应的销毁时的依赖(针对singleton bean),指定的bean会在当前bean销毁之前被销毁。
延迟初始化bean
如果你不想让一个singleton bean在ApplicationContext初始化时提前实例化,那么可以将bean设置为延迟实例化
如果一个bean设置为延迟实例化,而另一个非延迟实例化的singleton bean依赖它,那当IOC容器实例化singleton bean时,会确保它依赖的延迟bean也实例化
在容器层次上控制延迟初始化:
Spring 不能对一个prototype bean的整个生命周期负责,容器在初始化、配置、装配完一个prototype实例后,将它交给客户端,虽然就对该bean不闻不问了。
不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,但是prototype例外。
如果一个singleton类型的bean A需要引用另一个prototype类型的bean B,对于bean A来说,容器只会创建一次,这样就没法在需要的时候每次让容器为bean A提供一个新的bean B 实例,这个时候需要采用方法注入;
Request作用域:
<bean id="loginAction" scope="request"/>
针对每次HTTP请求,Spring容器会根据loginAction bean定义创建一个全新的LoginAction 实例,且该实例仅在当前HTTP request内有效。
Session作用域:
<bean id="userPreferences" scope="session"/>
针对某个HTTP Session, Spring容器会根据userPreferences bean定义创建一个全新的实例,且该实例仅在当前HTTP Session内有效。
Global Session作用域:
<bean id="userPreferences" scope="globalSession"/>
该作用越类似于HTTP Session作用域,但是它仅仅在基于portlet的web应用中才有意义。
作用域bean与依赖:
request、session、globalSession和自定义作用域需要<aop:scoped-proxy/>元素;
<bean id="userPreferences" scope="session"/>
<bean id="userManager" ref="userPreferences"/>
</bean>
此实例中,singleton bean userManager中注入了一个session作用域的userPreferences bean,这意味着userManager在理论上只会操作同一个userPreferences对象。
所以此时需要使用AOP代理
<bean id="userPreferences" scope="session">
<aop:scoped-proxy/>
</bean>
<bean id="userManager" ref="userPreferences"/>
</bean>
此时注入的对象其实是实现了和UserPreferences类一样的公共接口,即就是代理对象,并且不论底层选择了何种作用域,容器都能获取到真正的UserPreferences对象
但是<aop:scoped-proxy />不能和singleton或prototype的bean一起使用,所以,如果将一个prototype类型的bean注入到singleton中时需要使用lookup方法注入法
默认情况下,当一个bean有<aop:scope-proxy />标记时,Spring容器将为它创建一个基于CGLIB的类代理,此时需要将CGLIB库加到classpath中。CGLIB代理仅仅拦截public方法的调用;
如果想选择JDK代理,则需要将<aop:scoped-proxy />的属性proxy-target-class设置为false,但是此时类必须要实现至少一个接口。
自定义作用域:
自动以作用域需要实现 org.springframework.beans.factory.config.Scope接口
此接口提供四个方法来处理获取对象,移除对象和必要的时候销毁对象:
一、Object get(String name, ObjectFactory objectFactory) 从作用域中获取对象;
二、remove(String name) 从作用域中移除对象;
三、registerDestructionCallback(String name, Runnable destructionCallback) 注册作用域析构的回调方法,当作用域销毁或作用域中的某个对象销毁时会执行;
四、getConversationId() 处理作用域的会话标识。