Spring IOC 控制反转
IOC 是Inversion of control的简写,译为“控制反转”,它不是一门技术,而是一门设计思想,Spring 通过IOC 容器来管理所有java对象的实例化和初始化,控制对象与对象之间的依赖关系。
在传统的java应用中,一个类想要调用另一个类的属性或方法,通常会先在其代码中通过new Object 的方式将后者的对象创建出来,然后才能实现属性或方法的调用。即调用者掌控者被调用者对象创建的控制权。
在Spring 应用中,java对象创建的控制权是掌控在IOC容器手中,其大致步骤如下:
1、开发人员通过XML配置文件、注解、java配置类等方式,对java对象进行定义,例如在Xml配置文件中使用 标签,在java类上使用@Component注解等。
2、Spring 启动时,IOC 容器会自动根据对象定义,将这些对象创建并管理起来,这些被IOC容器创建并管理的对象被称为Spring Bean
3、当我们想要使用功能某个bean时,可以直接从IOC 容器中获取(例如通过ApplicationContext.getBean()方法),而不需要手动通过代码创建
new 对象是调用者主动的一方,它想要什么资源都会主动出击,自己创建,而在Spring应用中,IOC 容器掌控主动权,调用者则变成了被动的一方,被动的等待IOC 容器创建它所需要的对象。
这个过程在职责层面发生了控制权的反转,把原本调用者通过代码实现的对象创建,反转给IOC 容器来帮忙实现,这个过程就是spring 的控制反转。
IOC 工作原理
IOC 底层通过工厂模式、java反射机制、XML解析等技术,将代码的耦合度降低到最低限度,其主要步骤如下:
1、在配置文件(例如Bean.xml)中,各个对象以及它们之间的依赖关系进行配置;
2、可以把IOC 容器当做一个工厂,这个工厂的产品就是Spring Bean;
3、容器启动时会加载并解析这些配置文件,得到对象的基本信息以及它们之间的依赖关系。
4、IOC 利用java的反射机制,根据类名生成相应的对象,并根据依赖关系将这个对象注入到依赖它的对象中共。
由于对象的基本信息、对象之间的依赖关系都是在配置文件中定义的,并没有在代码中紧密耦合,因此即使对象发生改变,我们也只需要在配置文件中进行修改即可,而无须对java代码进行修改,这就是SPring IOC 实现解耦的原理。
IOC 实现
IOC 思想是基于IOC 容器实现的,IOC 容器底层其实就是一个Bean工厂。Spring 框架为我们提供了两种不同类型的IOC容器,分别是BeanFactory和ApllicationContext.
BeanFactory
BeanFactory是IOC容器的基本实现,也是Spring提供最简单的IOC 容器,它提供了IOC容器最近本的功能,由org.springframework.beans.factory.BeanFactory接口定义。
BeanFactory 采用懒加载(lazy-load)机制,容器在加载配置文件时并不会立即创建java对象,只有程序中获取这个对象时才会创建
例如:
// 采用BeanFactory 实现IOC
BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring/Beans.xml");
HelloWorld beanObj = beanFactory.getBean("helloWorld",HelloWorld.class);
beanObj.getMessage();
BeanFactory 是Spring 内部使用的接口,通常情况下不提供给开发人员使用。
ApplicationContext
\ApplicationContext 是BeanFactory 接口的子接口,是对BeanFactory 的扩展,ApplicationContext在BeanFactory 的基础上增加了许多企业级的工鞥,例如AOP、国际化、事务支持等。
ApplicationContext接口有两个常用的实现类:
实现类 | 描述 | 实例代码 |
---|---|---|
ClassPathXmlApplicationContext | 加载类路径 ClassPath 下指定的 XML 配置文件,并完成 ApplicationContext 的实例化工作 | ApplicationContext applicationContext = new ClassPathXmlApplicationContext(String configLocation); |
FileSystemXmlApplicationContext | 加载指定的文件系统路径中指定的 XML 配置文件,并完成 ApplicationContext 的实例化工作 | ApplicationContext applicationContext = new FileSystemXmlApplicationContext(String configLocation); |
例如:
ApplicationContext context = new ClassPathXmlApplicationContext("spring/Beans.xml");
HelloWorld obj =context.getBean("helloWorld",HelloWorld.class);
obj.getMessage();
BeanFactory 与ApplicationContext区别
BeanFactroy 是Spring 框架中IOC 容器的顶层接口,它只是用来定义一些基础功能,定义了一些基础规范,而ApplicationContext 是它的一个子接口,所有ApplicationContext 是具备BeanFactory提供的全部功能的.
通常,我们称BeanFactory为SpringIOC的基础容器,ApplicationContext 是容器的高级接口,比BeanFactory要拥有更多的功能,比如国际化支持和资源访问等.
启动 IoC 容器
- Java环境下启动IoC容器
- ClassPathXmlApplicationContext:从类的根路径下加载配置⽂件(推荐使⽤)
- FileSystemXmlApplicationContext:从磁盘路径上加载配置⽂件
- AnnotationConfigApplicationContext:纯注解模式下启动Spring
- Web环境下启动IoC容器
- 从xml启动容器
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--配置Spring ioc容器的配置⽂件-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--使⽤监听器启动Spring的IOC容器-->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
- 从配置类启动容器
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--告诉ContextloaderListener知道我们使⽤注解的⽅式启动ioc容器-->
<context-param>
<param-name>contextClass</param-name>
<paramvalue>
org.springframework.web.context.support.AnnotationConfigWebAppli
cationContext</param-value>
</context-param>
<!--配置启动类的全限定类名-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.lagou.edu.SpringConfig</param-value>
</context-param>
<!--使⽤监听器启动Spring的IOC容器-->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>