IoC是什么
java
IoC-Inversion of Control,即"控制反转",不是什么技术,而是一种设计思想。Java开发中,IoC意味着将设计好的对象交给IoC容器控制,再也不是传统的在对象内部直接控制。
web
谁控制谁,控制什么spring
传统Java SE程序中,直接在对象内部经过new建立对象,由程序主动去建立依赖对象;数组
IoC机制有专门的一个容器来建立这些对象,由IoC容器来控制对象的建立;session
谁控制谁?IoC容器控制对象;app
控制什么?主要控制了外部资源的获取(不仅是对象包括好比文件等)框架
为什么是反转,哪些方面反转了函数
传统的应用程序,在对象中主动控制去直接获取依赖对象,也就是正转;工具
反转则是由IoC容器帮忙建立及注入依赖对象;测试
为什么是反转?由容器进行查找及注入依赖对象,对象只是被动的接受依赖对象,因此是反转;
哪些方面反转了?依赖对象的获取被反转了
IoC能作什么
传统的应用程序在类内部主动建立依赖对象,从而致使类与类之间高耦合,难于测试;
IoC容器,把建立和查找依赖对象的控制权交给了容器,由容器进行注入,组合对象,因此对象与对象间是松耦合;
IoC很好的体现了面向对象设计法则之一 ——好莱坞法则:别找咱们,咱们找你;即由IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找
IoC 和 DI
DI - Dependency Injection,依赖注入:组件之间的依赖关系由容器在运行期间决定,形象的说,由容器动态的将某个依赖关系注入到组件中。
经过依赖注入机制,只需简单的配置,就可指定目标须要的资源,完成自身的业务逻辑,而不须要关心具体的资源来自何处。
关键点:
谁依赖于谁:固然是应用程序依赖IoC容器
为何须要依赖:应用程序须要IoC容器提供对象须要的外部资源
谁注入谁:IoC容器注入应用程序某个对象,应用程序依赖的对象
注入了什么:注入某个对象所需的外部资源(包括对象、资源、常量数据)
IoC 和 DI关系,实际上是同一律念的不一样角度描述,因为控制反转概念比较含糊,2004年又给出新的名字:依赖注入,相对IoC而言,”依赖注入“明确描述了”被注入对象依赖IoC容器配置依赖对象
Spring IoC容器的依赖,有两层含义:Bean依赖IoC容器,容器注入Bean的依赖资源
Bean依赖容器,指的是容器负责建立并管理Bean,是Bean和IoC容器间的依赖关系
容器注入Bean的依赖资源,依赖资源能够是Bean、外部文件、常量数据等,由容器负责组装Bean之间的依赖关系,此处的依赖为Bean之间的依赖关系,可认为是传统的类与类关联、聚合、组合关系
Spring IoC容器实现依赖资源注入的方式:
构造器注入:容器在实例化Bean时注入所需依赖资源,经过配置文件定义Bean中指定构造函数参数进行注入
setter注入:经过构造器、静态工厂或实例工厂实例好Bean后,经过调用Bean类的setter方法进行注入依赖
方法注入:经过配置方式替换掉Bean方法,也就是经过配置改变Bean方法功能
Spring IoC容器注入配置简写:
1、构造器注入
1)常量值
简写:<constructor-arg index="0" vlaue="xxx" />
全写:<constructor-arg index="0"><value>xxx</value></constructor-arg>
2)引用
简写:<constructor-arg index="0" ref="bean name" />
全写:<constructor-arg index="0"><ref bean="bean name" /></constructor-arg>
2、setter注入
1) 常量
简写:<property index="0" value="xxx" />
全写:<property index="0"><value>xxx</value></property>
2) 引用
简写:<property index="0" ref="bean name" />
全写:<property index="0"><ref bean="bean name" /></property>
3) 数组(array)
<property name="array name">
<array value-type="java.lang.String">
<value>xxx</value>
xxx
</array>
</property>
4) 列表(List)
<property name="list name">
<list value-type="java.lang.String">
<value>xxx</value>
...
</list>
</property>
5) 集合(set)
<property name="set name">
<set>
<value>xxx</value>
...
</set>
</property>
5) 字典(map)
<property name="map name">
<map key-type="java.lang.String" value-type="java.lang.String">
<entry key="xxx" value="xxx" />
...
</map>
</property>
6) Properties:
3、使用P命名空间简化setter注入
<beans xmlns:p="http://www.springframework.org/schema/p"> //指定P命名空间
<bean id="bean" class="com.spring.constroller.XXX" p:id="value" />
//常量setter注入方式,等价于<property name="id" value="value" />
<bean id="bean2" class="com.spring.controller.XXX" p:id-ref="xxx" />
//引用setter注入方式,其等价于<property name="id" ref="xxx" />
</beans>
BeanFactory和ApplicationContext
Spring经过xml配置文件描述Bean和Bean直接的依赖关系,利用Java语言的反射机制实例化Bean并创建Bean之间的依赖关系。
BeanFactory(org.springframework.beans.factory.BeanFactory)是Spring框架最核心的接口,提供了高级IoC的配置机制。
ApplicationContext(应用上下文,org.springframework.context.ApplicationContext)创建在BeanFactory基础上,提供了面向应用的gongneng,提供了国际化支持和框架事件体系。
通常地,称BeanFactory为IoC容器,而称ApplicationContext为应用上下文。
从用途上进行划分,BeanFactory是Spring框架的基础设施,面向Spring;ApplicationContext面向Spring框架的使用者
初始化BeanFactory
使用Spring配置文件提供配置信息,经过BeanFactory装载配置文件,启动Spring IoC容器。
经过BeanFactory启动IoC容器时,并不会初始化配置文件中的Bean,初始化动做发生在第一个调用时。
注意:初始化BeanFactory时,必须提供一种日志框架,好比Log4j,在类路径下提供Log4j配置文件,这样启动Spring容器才不会报错
ApplicationContext介绍
如若BeanFactory是Spring的心脏,那ApplicationContext就是Spring完整的身躯。ApplicationContext由BeanFactory派生而来,提供了面向实际应用的功能。
ApplicationContext体系结构
其主要实现类是ClassPathXMLApplicationContext和FileSystemXMLApplicationContext,前者默认从类路径加载配置文件,后者从文件系统中装载配置文件。
ApplicationContext初始化
和BeanFactory初始化类似,ApplicationContext初始化也很简单,若是配置文件放在类路径下,优先使用ClassPathXMLApplicationContext实现类:
ApplicationContext context = new ClassPathXMLApplicationContext("com/bbtao/context/beans.xml");
等同于: "classpath:com/bbtao/context/beans.xml"
若是配置文件放在文件系统路径下,优先考虑FileSystemXMLApplicationContext实现类:
ApplicationContext context = new FileSystemXMLApplicationContext("com/bbtao/context/beans.xml");
等同于: "file:com/bbtao/context/beans.xml"
ApplicationContext与BeanFactory的重大区别:
BeanFactory在初始化IoC容器时,并未实例化Bean,直到第一次访问调用某个Bean时才进行实例化操做;
ApplicationContext,在初始化应用上下文时就实例化全部单实例的Bean。
AnnotationConfigApplicationContext:
Spring 3.0支持基于类注解的配置方式,主要功能源自Spring的JavaConfig子项目。一个标注@Configuration注解的POJO便可提供Spring所需的Bean配置信息
Spring为基于注解类的配置提供了专门的ApplicationContext实现类:AnnotationConfigApplicationContext
WebApplicationContext
WebApplicationContext,专为Web应用准备的,容许从相对于Web根目录的路径中装载配置文件完成初始化工做
整个WebApplicationContext对象做为属性放到ServletContext中,以便Web应用环境能够访问到Spring应用上下文。为此,Spring提供一个工具类WebApplicationContextUtils,经过该类的getWebApplicationContext(ServletContext sc),就可从ServletContext中获取WebApplicationContext实例。
Spring 2.0在WebApplicationContext中为Bean添加了三个新的做用域:request做用域、session做用域和global session做用域。
WebApplicationContext中定义了一个常量ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,上下文启动时,WebApplicationContext实例以此键放置在ServletContext的属性列表中。所以,经过如下语句从Web容器中获取WebApplicationContext:
WebApplicationContext context = (WebApplicationContext)servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
WebApplicationContext初始化
初始化方式,和BeanFactory、ApplicationContext有所不一样,由于WebApplicationContext初始化时须要ApplicationContext实例,也就是说WebApplicationContext必须在拥有Web容器的前提下才能完成启动工做。
Spring提供了用于启动WebApplicationContext的Servlet和Web容器监听器:
org.springframework.web.context.ContextLoaderServlet
org.springframework.web.context.ContextLoaderListener
二者内部都实现了启动WebApplicationContext实例的逻辑,根据Web容器的状况,在web.xml文件中进行配置就能够了
示例(ContextLoaderListener)
<!-- 指定Spring配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 声明Web容器监听器 -->
<listener>
<listener-class>org.springframe.web.context.ContextLoaderListener</listener-class>
</listener>
ContextLoaderListener经过Web容器上下文参数contextConfigLocation获取Spring配置文件的位置。用户也能够指定多个配置文件,用逗号、空格或冒号分割都可。
不支持容器监听器的低版本Web容器中,采用ContextLoaderServlet完成启动工做:
示例(ContextLoaderServlet):
<!-- 指定Spring配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 声明自动启动的Servlet -->
<servlet>
<servlet-name>contextLoaderServlet</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<!-- 启动顺序 -->
<load-on-startup>1</load-on-startup>
</servlet>
因为WebApplicationContext须要使用日志功能,将Log4j的配置文件放到类路径(/WEB-INF/classess/)下,Log4j引擎可顺利启动。若是Log4j配置文件放在其余位置,那必须在web.xml中指定配置文件位置。
Spring为Log4j引擎提供了两个实现类:Log4jConfigServlet,和Log4jConfigListener;无论采用哪一种方式,必须保证Log4j配置信息先于Spring配置文件加载。
示例:
<!-- 指定Spring配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContex.xml</param-value>
</context-param>
<!-- 指定Log4j配置文件 -->
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/log4j.properties</param-value>
</context-param>
<!-- 配置Log4j的自启动Servlet -->
<servlet>
<servlet-name>log4jConfigServlet<servlet-name>
<servlet-class>org.springframework.web.util.Log4jConfigServlet</servlet-class>
<!-- 指定Log4jConfigServlet的启动顺序,必定要先于WebApplicationContext启动 -->
<load-on-startup>1</load-on-startup>
</serlvet>
<!-- 声明WebApplicationContext的自启动Servlet-->
<servlet>
<servlet-name>contextLoaderServlet</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
若是使用Web监听器,则必须将Log4jConfigListener放在ContextLoaderListener的前面,这样才保证Log4j的启动先于WebApplicationContext完成。