IoC 概述
概念
IoC(Inverse of Control)控制反转是 Spring 容器的内核,AOP、声明式事务等都是基于该概念;
从概念上来说,可以用
DI(Dependency Injection)依赖注入来代替Ioc的理解:让调用类对某一接口的依赖关系由第三方(容器或协作类)注入,以移除调用类对某一接口的依赖;
Ioc 的类型
从注入方法来来看,Ioc主要划分为 3 类:
属性注入,构造函数注入,接口注入;
Spring 支持其中的属性注入,构造函数注入(同时还支持派生出来的工厂方法注入);
Spring 对 Ioc 的支持是基于 Java reflect 类反射来实现的;
IoC 容器
BeanFactory 和 ApplictionConext
Spring 通过配置文件描述 Bean 之间的依赖关系,再由Java的反射功能实例化 Bean,并建立 Bean 之间的依赖关系;
BeanFactory (com.springframework.beans.factory.BeanFactory)
IoC 容器:是 Spring 最核心的功能接口,提供了高级 IoC 的配置;
AppliactionContext(
com.springframework.context.ApplicationContext)应用上下文 :建立在 BeanFactory 之上,同时实现更多的应用功能,在开发过程中一般更多使用ApplicationConext 作为 IoC 容器对象,因此 ApplictionContext 也被称为 Spring 容器;
※ BeanFactory 主要面向 Spring 框架开发本身,ApplictionContext 面对 Spring 框架应用开发者,几乎所有的场合都会使用 ApplicationContext 而非底层的 BeanFactory;
※ ApplicationContext 和 BeanFactory 在初始化上有一个区别:
BeanFactory 在初始化容器时,不会实例化Bean,直到访问第一个 Bean 时才会实例化该Bean;
ApplicationContext 在初始化上下文的时候会实例化所有单实例的Bean,因此一般初始化时间会比 BeanFactory 更久,以换取之后更快的Bean实例调用速度;
BeanFactory 和 ApplictionContext 常用的API
T getBean(String name,Class<T> requiredType) | 返回一个指定Bean的示例 |
Class<T> getType(String name) | 返回指定名称的Bean的类型 |
其中 ApplicationContext 的子类 ConfigurableApplication 拓展提供了 refresh() 、close()法,为 ApplictionContext 的具体类提供了刷新、关闭上下文的能力;
以上是与Bean使用相关的API ,完整 API 见官方完整的 API 文档;
ApplictionContext 的常用实现类
ClassPathXmlApplicationContext 和 FileSystemXmlApplicationContext
这两者主要用于加载使用 XML ,注解方式配置的 Bean,前者用于加载类路径下的配置文件,后者则使用系统路径加载配置文件;
//使用 ClassPathXmlApplicationContext 加载指定Bean,该Bean的配置文件路径为 myporject/src/main/resources/site/assad/demo/beans.xml
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("site/assad/demo/beans.xml");
Car car = ctx.getBean("car1",Car.class);
//也可以加载一组指定的xml配置文件,Spring会自动整合为一个配置文件;
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("conf/bean1.xml","conf/bean2.xml");
AnnotationConfigApplication
该具体类用于加载基于JavaConfig类配置的Bean
ApplictionContext ctx = new AnnnoConfigAppliction(Bean.class);
Car car = ctx.getBean("car1",Car.class);
GenericGroovyApplicationContext
该具体类用于加载基于Groovy DSL配置的Bean
ApplictionContext ctx = new GenericGroovyApplicationContext("classpath:site/assad/demo/groovy-beans.groovy");
Car car = ctx.getBean("car1",Car.class);
WebApplicationContext 体系
WebApplicationContext 是为 Web 应用准备的 ApplicationContext 实现类,它允许从相对于 Web 根目录的路径中装载配置文件以完成初始化工作,同时可以获取 ServletContext 的引用,将整个 Web 应用上下文对象作为属性放到 ServletContext 之中,以便 Web 应用环境可以访问 Spring 应用的上下文;
在非 Web 环境下,Bean 只有 singleton , prototype 2种作用域,WebApplictionContext 为 Bean 增加了3种作用域:request,session,global session ;
同时 WebApplictionContext 定义一个常量 ROOT_WEB_APPLICTION_CONTEXT_ATTRIBUTE 用于在上下文启动时,在 ServletContext 的属性列表中存放 WebApplictionContext 实例,
如下:
WebApplicationContext wac = (WebApplicationContext)servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICTION_CONTEXT_ATTRIBUTE);
ConfigurableWebApplicationContext 是 WebApplicationContext 的工具子类
,ConfigurableApplicationContext 允许通过配置的方式实例化 WebApplicationContext ,其定义了2个重要的方法:
setServletContext(ServletContext servletContext) | 为Spring设置Web上下文 |
setConfigLocations(String[] configLocations) | 设置Spring 配置文件地址,一般 破日子文件是相对于 Web 根目录的,如:/WEB-INF/assad-dao.xml,/WEB-INF/assad-service.xml 等;也可以使用带资源类型前缀的地址,如:classpath:site/assad/beans.xml |
WebApplicationConetxt 的初始化配置
WebApplicationConetxt 的初始化需要 ServletContext 实例,即必须在拥有 Web 容器的前提下才能启动该上下文;
可以在
web.xml 中
配置自启动的 Servlet 或 ServletContextListener(Web容器监听器)来启动 WebApplicationConetxt,
Spring 分别提供了以下2个类用于实现这2个功能:
- org.springframework.web.context.ContextLoaderServlet
- org.springframework.web.context.ContextLoaderListener
以详解多种Bean装配方式的 WebApplicationContext 初始化:
通过xml配置Bean的初始化
① 通过 ContextLoaderListener 启动
<web-app>
....
<!--指定配置文件-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/assad-dao.xml,/WEB-INF/assad-dao.xml</param-value>
</context-param>
.....
<!--声明 Web 容器监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
① 通过 ContextLoaderServlet 启动
<web-app>
....
<!--指定配置文件-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/assad-dao.xml,/WEB-INF/assad-dao.xml</param-value>
</context-param>
.....
<!--声明自启动的Servlet-->
<servlet>
<servlet-name>springContextLoaderServlet</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
</web-app>
通过JavaConfig配置Bean的初始化
对于使用标注 @Configuration 的Java 类提供配置信息,则 web.xml 需要按照类似以下的方式配置(以下只演示ContextLoaderListener 方式,另一种方式类似):
<web-app>
....
<!--让Spring使用 AnnotationConfigWebApplication 而非 XmlWebApplicationContext启动容器-->
<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
<!--指定标注了 @Configuration 的配置类,多个类可以使用逗号或空格分开-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>site.assad.AppConfig1,site.assad.AppConfig2</param-value>
</context-param>
.......
<!--声明 Web 容器监听器,ContextLoaderListener将使用上配置使用的AnnotationConfigWebApplication根据contextConfigLocation启动Spring容器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
通过 Groovy 配置Bean的初始化
以下只演示ContextLoaderListener 方式,另一种方式类似:
<web-app>
....
<!--让Spring使用 AnnotationConfigWebApplication 而非 XmlWebApplicationContext启动容器-->
<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.GroovyWebApplicationContext
</param-value>
</context-param>
<!--指定Groovy配置文件-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>Classpath*:conf/spring-mvc.groovy</param-value>
</context-param>
.......
<!--声明 Web 容器监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
Log4J 引擎的配置
WebApplicationContext 需要使用日志功能,可以将 Log4J 的配置文件放置在类路径 WEB-INF/classes 下,此时 Log4J 引擎可以自动启动,如果 Log4J 配置文件位于其他位置,可以按照以下的方式配置(以ContextLoaderServlet的方式示例):
<web-app>
....
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/assad-dao.xml,/WEB-INF/assad-dao.xml</param-value>
</context-param>
......
<!--指定Log4J配置文件的位置-->
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/log4j2.xml</param-value>
</context-param>
<!--装载Log4J配置文件的自启动Servlet-->
<servlet>
<servlet-name>log4jConfigServlet</servlet-name>
<servlet-class>org.springframework.web.util.Log4jConfigServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
......
<servlet>
<servlet-name>springContextLoaderServlet</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
</web-app>
※
注意必须保证在装载Spring配置文件之前先装载Log4J配置文件信息;