控制反转的类型

控制反转(IOC)旨在提供一种更简单的机制,来设置组件的依赖项,并在整个生命周期管理这些依赖项。通常,控制反转可以分成两种子类型:依赖注入(DI)和依赖查找(DL),这些子类型各自又可以被进一步分解为 IOC 服务的具体实现

1. 依赖查找

1.1 依赖拉取

依赖拉取(Dependency Pull),即根据需要,从注册表中提取依赖项,以下代码显示了基于 Spring 的依赖拉取

  1. public class DependencyPull {
  2. public static void main(String[] args) {
  3. ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring/app-context.xml");
  4. ctx.getBean("renderer", MessageRenderer.class);
  5. }
  6. }
1.2 上下文依赖查找

上下文依赖查找(contextualized dependency lookup,CDL),同样属于依赖查找的子类型,和依赖拉取有点类似,但在 CDL 中,查找是针对管理资源的容器执行的,这个容器通常由应用程序服务器或框架(Tomcat、JBoss、Spring)提供,比如以下代码显示了一个提供依赖查找服务的容器接口

  1. public interface Container {
  2. // 根据key获取相应的依赖项
  3. Object getDependency(String key);
  4. }

CDL 通过让组件实现以下代码接口来进行工作

  1. public interface ManagedComponent {
  2. void performLookup(Container container);
  3. }

组件需要实现该接口,当容器准备好将依赖项传递给组件时,会依次调用每个组件的 performLookup() 方法,然后组件就可以使用 Container 接口查找所需的依赖项

  1. public class ContextualizedDependencyLookup implements ManagedComponent {
  2. private Dependency dependency;
  3. @Override
  4. public void performLookup(Container container) {
  5. this.dependency = (Dependency) container.getDependency("myDependency");
  6. }
  7. @Override
  8. public String toString() {
  9. return dependency.toString();
  10. }
  11. }

2. 依赖注入

2.1 构造函数注入

当在组件的构造函数中提供依赖项时,就会发生构造函数依赖注入

  1. public class ConstructorInjection {
  2. private Dependency dependency;
  3. public ConstructorInjection(Dependency dependency) {
  4. this.dependency = dependency;
  5. }
  6. @Override
  7. public String toString() {
  8. return dependency.toString();
  9. }
  10. }
2.2 setter 函数注入

Ioc 容器通过 JavaBean 样式的 setter 方法注入组件的依赖项

  1. public class SetterInjection {
  2. private Dependency dependency;
  3. public void setDependency(Dependency dependency) {
  4. this.dependency = dependency;
  5. }
  6. @Override
  7. public String toString() {
  8. return dependency.toString();
  9. }
  10. }

在 Spring 中,还支持另一种被称为字段注入(field injection)的注入类型,在后面学习使用 @Autowire 注解进行自动装配时将介绍该注入类型

Spring 中的控制反转

1. Bean 和 BeanFactory

Spring 的依赖注入容器的核心是 BeanFactory,它负责管理组件,包括依赖项以及它们的生命周期。如果我们想获得一个组件(Bean),就必须创建一个实现了 BeanFactory 接口的实例,并对其进行配置

虽然 BeanFactory 可以通过编程方式配置,但更常见的做法是使用某种配置文件在外部对其进行配置。Bean 配置可以由实现 BeanDefinition 接口的类的实例来表示,对于任何实现了 BeanDefinitionReader 接口的 BeanFactory 实现类来说,都可以使用 PropertiesBeanDefinitionReader 或 XmlBeanDefinitionReader 从配置文件读取 BeanDefinition 数据

定义一组接口:

  1. public interface Oracle {
  2. String output();
  3. }
  4. public class OracleImpl implements Oracle {
  5. @Override
  6. public String output() {
  7. return "hello world";
  8. }
  9. }

接下来我们来看一看,Spring 的 BeanFactory 如何被初始化并用于获取 Bean 实例

  1. public class XmlConfigWithBeanFactory {
  2. public static void main(String[] args) {
  3. // DefaultListableBeanFactory是Spring提供的两个主要BeanFactory实现之一
  4. DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
  5. XmlBeanDefinitionReader rdr = new XmlBeanDefinitionReader(factory);
  6. // 使用XmlBeanDefinitionReader从XML文件读取BeanDefinition信息
  7. rdr.loadBeanDefinitions(new ClassPathResource("spring/xml-bean-factory-config.xml"));
  8. // 使用在XML配置文件中配置的名称oracle来获取bean
  9. Oracle oracle = (Oracle) factory.getBean("oracle");
  10. System.out.println(oracle.getInfo());
  11. }
  12. }
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <bean id="oracle" name="oracle" class="com.example.OracleImpl"/>
  6. </beans>

ApplicationContext 接口是 BeanFactory 的一个扩展,除了 DI 服务外,还提供其他如事务和 AOP 等服务。在开发基于 Spring 的应用程序时,建议通过 ApplicationContext 接口与 Spring 交互

2. 设置 Spring 配置

2.1 XML 配置

对于 XML 配置,需要声明应用程序需要的由 Spring 提供的名称空间基础信息,下面所示配置仅声明用于定义 bean 的名称空间

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:p="http://www.springframework.org/schema/p"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <bean id="provider" class="com.example.HelloWorldMessageProvider"/>
  7. <bean id="render" class="com.example.StandardOutMessageRender"
  8. p:messageProvider-ref="provider"/>
  9. </beans>
2.2 注解配置

要想在应用程序使用 Spring 的注解支持,需要在 XML 配置中声明

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/context
  8. http://www.springframework.org/schema/context/spring-context.xsd">
  9. <context:component-scan base-package="com.example" />
  10. </beans>

<context:component-scan> 标记告诉 Spring 扫描代码,从而找到 @Component 等注解注入的 bean,以及支持在指定包(及其所有子包)下使用 @Autowire 等注解的 bean

2.3 Java 配置

配置类使用 @Configuration 注解,并包含用 @Bean 注解的方法,这些方法由 IOC 容器直接调用来实例化 bean,bean 名称与用于创建它的方法的名称相同

  1. @Configuration
  2. public class HelloWorldConfiguration {
  3. @Bean
  4. public MessageProvider provider() {
  5. return new HelloWorldMessageProvider();
  6. }
  7. @Bean
  8. public MessageRender render() {
  9. StandardOutMessageRender render = new StandardOutMessageRender();
  10. render.setMessageProvider(provider());
  11. return render;
  12. }
  13. }

如果想从该类中读取配置信息,需要一个不同的 ApplicationContext 实现

  1. public class HelloWorldSpringAnnotated {
  2. public static void main(String[] args) {
  3. AnnotationConfigApplicationContext ctx
  4. = new AnnotationConfigApplicationContext(HelloWorldConfiguration.class);
  5. MessageRender render = ctx.getBean("render", MessageRender.class);
  6. render.render();
  7. }
  8. }

3. setter 注入

使用 XML 配置来配置 setter 注入,需要在 <bean> 标记下指定 <property> 标记,为其注入一个依赖项

  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xmlns:p="http://www.springframework.org/schema/p"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <bean id="provider" class="com.example.HelloWorldMessageProvider"/>
  6. <bean id="render" class="com.example.StandardOutMessageRender">
  7. <property name="messageProvider" ref="provider"/>
  8. </bean>
  9. </beans>

如果使用注解,只需要向 setter 方法添加一个 @Autowired 注解

  1. @Service("render")
  2. public class StandardOutMessageRender implements MessageRender {
  3. ...
  4. @Override
  5. @Autowired
  6. public void setMessageProvider(MessageProvider messageProvider) {
  7. this.messageProvider = messageProvider;
  8. }
  9. }

4. 构造函数注入

  1. public class ConfigurableMessageProvider implements MessageProvider {
  2. private String message;
  3. public ConfigurableMessageProvider(String message) {
  4. this.message = message;
  5. }
  6. @Override
  7. public String getMessage() {
  8. return null;
  9. }
  10. }

使用 XML 方式注入

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:c="http://www.springframework.org/schema/c"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <bean id="oracle" name="oracle" class="com.example.OracleImpl"/>
  7. <!-- 使用 <constructor-arg> 标记 -->
  8. <bean id="messageProvider" class="com.example.ConfigurableMessageProvider">
  9. <constructor-arg value="hello world" />
  10. </bean>
  11. <!-- 使用c名称空间 -->
  12. <bean id="provider" class="com.example.ConfigurableMessageProvider"
  13. c:message="hello world"/>
  14. </beans>

使用注解方式

  1. @Service
  2. public class ConfigurableMessageProvider implements MessageProvider {
  3. private String message;
  4. @Autowired
  5. public ConfigurableMessageProvider(
  6. @Value("hello world") String message) {
  7. this.message = message;
  8. }
  9. @Override
  10. public String getMessage() {
  11. return null;
  12. }
  13. }

Spring 控制反转和依赖注入的更多相关文章

  1. spring 控制反转与依赖注入原理-学习笔记

    在Spring中有两个非常重要的概念,控制反转和依赖注入:控制反转将依赖对象的创建和管理交由Spring容器,而依赖注入则是在控制反转的基础上将Spring容器管理的依赖对象注入到应用之中: 所谓依赖 ...

  2. Spring控制反转与依赖注入(IOC、DI)

    IOC: 反转控制   Inverse Of Control DI:依赖注入 Dependency Injection 目的:完成程序的解耦合 解释:在应用系统的开发过程中,有spring负责对象的创 ...

  3. Spring控制反转(依赖注入)的最简单说明

    1.常规方式实现实例化 1.1已有角色如下: 一个接口Interface,两个接口实现类InstatnceA.InstanceB,一个调用类User 1.2当前实例化InstanceA如下: Inte ...

  4. 对spring控制反转以及依赖注入的理解

    一.说到依赖注入(控制反转),先要理解什么是依赖. Spring 把相互协作的关系称为依赖关系.假如 A组件调用了 B组件的方法,我们可称A组件依赖于 B组件. 二.什么是依赖注入. 在传统的程序设计 ...

  5. 轻松了解Spring中的控制反转和依赖注入(二)

    紧接上一篇文章<轻松了解Spring中的控制反转和依赖注入>讲解了SpringIOC和DI的基本概念,这篇文章我们模拟一下SpringIOC的工作机制,使我们更加深刻的理解其中的工作. 类 ...

  6. 轻松了解Spring中的控制反转和依赖注入(一)

    我们回顾一下计算机的发展史,从最初第一台计算机的占地面积达170平方米,重达30吨,到现如今的个人笔记本,事物更加轻量功能却更加丰富,这是事物发展过程中的一个趋势,在技术领域中同样也是如此,企业级Ja ...

  7. spring学习总结一----控制反转与依赖注入

    spring作为java EE中使用最为广泛的框架,它的设计体现了很多设计模式中经典的原则和思想,所以,该框架的各种实现方法非常值得我们去研究,下面先对spring中最为重要的思想之一----控制反转 ...

  8. 简单了解Spring的控制反转和依赖注入

    浅谈控制反转(Inversion of Control,IOC) 我们首先先来了解一下控制二字,也就是在控制"正"转的情况下,在任何一个有请求作用的系统当中,至少需要有两个类互相配 ...

  9. Spring的控制反转和依赖注入

    Spring的官网:https://spring.io/ Struts与Hibernate可以做什么事? Struts, Mvc中控制层解决方案 可以进行请求数据自动封装.类型转换.文件上传.效验… ...

随机推荐

  1. 360浏览器兼容模式下jsp页面访问不到js文件

    360浏览器兼容模式下jsp页面访问不到js文件 查看自己js中的语法问题,不要用ES6的语法,编译不了故找不到js文件 const var of 码出高效 java 比较 所有整型包装类对象之间值的 ...

  2. MySQL提权之启动项提权

    关于MySQL的启动项提权,听其名知其意.就是将一段 VBS脚本导入到  C:\Documents and Settings\All Users\「开始」菜单\程序\启动 下,如果管理员重启了服务器, ...

  3. python实现掘金定时签到抽奖

    python实现掘金定时签到抽奖 一. 概述 这里记录一下使用 python 实现掘金定时签到抽奖.首先需要登录掘金,进入签到页面,按 F12 打开浏览器的调试面板,选择 Network,选择 XHR ...

  4. 将Cesium Tools用于更好的构建管理

    Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://cesium.coinidea.com/ Cesium技术正在给建筑业带来革命性的变化.我们与 partn ...

  5. Sentry 开发者贡献指南 - 什么是 Scope, 什么是 Hub?

    当一个事件被捕获并发送到 Sentry 时,SDK 会将该事件数据与来自当前 scope 的额外信息合并.SDK 通常会在框架集成中为您自动管理 scope,您无需考虑它们.但是,您应该知道 scop ...

  6. JavaScript设计原则与编程技巧

    1 设计原则概述 <UNIX/LINUX设计哲学>设计准则 ① 小既是美. ② 每个程序只做一件事情. ③ 快速建立原型. ④ 舍弃高效率而取可移植性. ⑤ 避免强制性的图形化界面交互. ...

  7. MySQL语句SQL应用

    目录 一:sql语句 1.什么是SQL语句? 二:基本SQL语句之库操作 三:基本SQL语句之表操作 1.查看当前所在库名称 2.切换数据库 四:基本SQL语句之记录操作 五:创建表的完整语法 一:s ...

  8. CSS之常见布局|常用单位|水平垂直居中

    常见布局: 1. 流式布局:百分比布局,宽高.margin.pinding都是百分比 2. 固定布局:盒子的宽高固定,如:margin.padding等 3. 浮动布局:float 4. 弹性布局:f ...

  9. Python Study Note 1

    Learn The First Day OF Operation Notes

  10. PyTorch 1.4 中文文档校对活动正式启动 | ApacheCN

    一如既往,PyTorch 1.4 中文文档校对活动启动了! 认领须知 请您勇敢地去翻译和改进翻译.虽然我们追求卓越,但我们并不要求您做到十全十美,因此请不要担心因为翻译上犯错--在大部分情况下,我们的 ...