重新认识IoC

1. IoC发展简介

  • 什么是IoC
    wiki

  • IoC简史

    • 1983年,Richard E. Sweet 在《The Mesa Programming Environment》中提出"Hollywood Principle"(好莱坞原则)
    • 1988年,Ralph E. Johnson & Brian Foote 在《Designing Reusable Classes》中提出"Inversion of control"(控制反转)
    • 1996年,Michael Mattson 在 《Object-Oriented Frameworks, A survey of methodological
      issues》中将’Inversion of controT 命名为"Hollywood principle"
    • 2004年,Martin Fowler 在《Inversion of Control Containers and the Dependency Injection pattern》中提出了自己对loC以及DI的理解
    • 2005年,Martin Fowler 在《InversionOfControl》对 IoC 做出进一步的说明

2. IoC主要实现策略:面试官总问IoC和DI的区别,他真的理解吗?

*(https://en.wikipedia.org/wiki/Inversion_of_control)
Implementation techniques 小节的定义:
"In object-oriented programming, there are several basic techniques to implement inversion of control. These are:

  • Using a service locator pattern

  • Using dependency injection, for example

    • Constructor injection
    • Parameter injection
    • Setter injection
    • Interface injection
  • Using a contextualized lookup

  • Using template method design pattern

  • Using strategy design pattern

  • 《Expert One-on-One™ J2EE™ Development without EJB™》提到的主要实现策略: “IoC is a broad concept that can be implemented in different ways. There are two main types:

    • Dependency Lookup: The container provides callbacks to components, and a lookup context This is the EJB and Apache Avalon approach. It leaves the onus on each component to use container APIs to look up resources and collaborators. The Inversion of Control is limited to the container invoking callback methods that application code can use to obtain resources.
    • Dependency Injection: Components do no look up; they provide plain Java methods enabling the container to resolve dependencies. The container is wholly responsible for wiring up components, passing resolved objects in to JavaBean properties or constructors. Use of JavaBean properties is called Setter Injection; use of constructor arguments is called Constructor Injection. "

3. IoC容器的职责:IoC除了依赖注入,还涵盖哪些职责呢?

*(https://en.wikipedia.org/wiki/lnversion_of_control)
在Overview小节中提到:

Inversion of control serves the following design purposes:

  • To decouple the execution of a task from implementation.
  • To focus a module on the task it is designed for.
  • To free modules from assumptions about how other systems do what they do and instead rely on contracts.
  • To prevent side effects when replacing a module.

Inversion of control is sometimes facetiously referred to as the 'Hollywood Principle: Don’t call us, well call you¹>.

通用职责

  • 依赖处理
    • 依赖查找
    • 依赖注入
  • 生命周期管理
    • 容器
    • 托管的资源(Java Bean 或其他资源)
  • 配置
    • 容器
    • 外部化配置
    • 托管的资源(Java Bean 或其他资源)

4. IoC容器的实现

主要实现

  • Java SE
    • Java Beans
      依赖查找在Java中很早就有了
    • Java ServiceLoader SPI
    • JNDI (Java Naming and Directory Interface)
  • Java EE
    • EJB (Enterprise Java Beans)
    • Servlet
  • 开源
    • Apache Avalon (https://avalon.apache.org/closed.html)
      和 EJB类似,是开源轻量级依赖查找框架
    • PicoContainer (http://picocontainer.com/)
      《Expert One-on-One™ J2EE™ Development without EJB™》第六章提到Spring Framework技术灵感来自PicoContainer
    • Google Guice (https://github.com/google/guice)
      当前国外除了Spring Framework比较流行的之一
    • Spring Framework(https://spring.io/projects/spring-framework)

5. 传统IoC容器实现

Java Beans作为IoC容器

  • 特性
    • 依赖查找
    • 生命周期管理
    • 配置元信息
    • 事件
      Spring 也是基于Java的事件机制来做的
    • 自定义
    • 资源管理
    • 挺久化
  • 规范
    • JavaBeans (https://docs.oracle.com/javase/tutorial/javabeans/)
    • Bean Context (https://docs.oracle.com/javase/8/docs/technotes/guides/beans/spec/beancontext.html)

6. 轻量级IoC容器:如何界定IoC容器的“轻重”?

  • 《Expert One-on-One™ J2EE™ Development without EJB™》 认为轻量级容器的特征:
    • A container that can manage application code.
      可以管理我们的应用代码的运行
    • A container that is quick to start up.
      快速启动
    • A container that doesn’t require any special deployment steps to deploy objects within it.
      (相对EJB)不需要特殊的配置步骤部署
    • A container that has such a light footprint and minimal API dependencies that it can be run in a variety of environments.
      比较轻量级的内存占用及最小化API依赖
    • A container that sets the bar for adding a managed object so low in terms of deployment effort and performance overhead that it’s possible to deploy and manage fine-grained objects, as well as coarse-grained components.
      即部署上的效率

  • 《Expert One-on-One™ J2EE™ Development without EJB™^ 认为轻量级容器的好处:
    • Escaping the monolithic container
      释放单体容器
    • Maximizing code reusability
      最大化代码复用
    • Greater object orientation
      更大程度上的面向对象(EJB不是很好的面向对象实现方式)
    • Greater productivity
      更大化产品化
    • Better testability
      JUNIT 和单元测试

7. 依赖查找 VS. 依赖注入

类型 依赖注入 实现便利性 代码侵入性 API依赖性 可读性
依赖查找 主动获取 相对繁琐 侵入业务逻辑 依赖容器API 良好
依赖注入 被动提供 相对便利 低侵入性 不依赖容器API 一般

8. 构造器注入 VS. Setter 注入

  • Spring Framework对构造器注入与Setter的论点:

“The Spring team generally advocates constructor injection, as it lets you implement application components as immutable objects and ensures that required dependencies are not null. Furthermore, constructor-injected components are always returned to the client (calling) code in a fully initialized state. As a side note, a large number of constructor arguments is a bad code smell, implying that the class likely has too many responsibilities and should be refactored to better address proper separation of concerns.

Setter injection should primarily only be used for optional dependencies that can be assigned reasonable default values within the class. Otherwise, not-null checks must be performed everywhere the code uses the dependency. One benefit of setter injection is that setter methods make objects of that class amenable to reconfiguration or re-injection later. Management through JMX MBeans is therefore a compelling use case for setter inject ion.”

  • 《Expert One-on-One™ J2EE™ Development without EJB™》认为 Setter 注入的优点:

    Advantages of Setter Injection include:

    • Java Be an properties are well supported in IDEs.
    • Java Bean properties are self-documenting.
    • Java Bean properties are inherited by subclasses without the need for any code.
    • It’s possible to use the standard Java Beans property-editor machinery for type conversions if necessary.
    • Many existing JavaBeans can be used within a JavaBean-oriented loC container without modification.
    • If there is a corresponding getter for each setter (making the property readable, as well as writable), it is possible to ask the component for its current configuration state. This is particularly useful if we want to persist that state: for example, in an XML form or in a database. With Constructor Injection, there’s no way to find the current state.
    • Setter Injection works well for objects that have default values, meaning that not all properties need to be supplied at runtime.

  • 《Expert One-on-One™ J2EE™ Development without EJB™》认为 Setter 注入的缺点:

Disadvantages include:
The order in which setters are called is not expressed in any contract. Thus, we sometimes need to invoke a method after the last setter has been called to initialize the component. Spring provides the
org.springframework.beans.factory.InitializingBean interface for this; it also provides the ability to invoke an arbitrary init method. However, this contract must be documented to ensure correct use outside a container.

Not all the necessary setters may have been called before use. The object can thus be left partially configuredy

  • 《Expert One-on-One™ J2EE™ Development without EJB™》认为构造器注入的缺点:

    Disadvantages include:

    • Although also a Java-language feature, multi-argument constructors are probably less common in existing code than use of Java Bean properties.
    • Java constructor arguments don’t have names visible by introspection.
    • Constructor argument lists are less well supported by IDEs than Java Bean setter methods.
    • Long constructor argument lists and large constructor bodies can become unwieldy.
    • Concrete inheritance can become problematic.
    • Poor support for optional properties, compared to Java Beans
    • Unit testing can be slightly more difficult
    • When collaborators are passed in on object construction, it becomes impossible to change the reference held in the

9. 面试题精选

  • 沙雕面试题 - 什么是IoC?

答:简单地说,IoC是反转控制,类似于好莱坞原则,主要有依赖查找和依赖注入实现。

按照IoC的定义,很多东西都是IoC,JavaBeans是IoC的一个容器实现,Servlet容器也是IoC的实现,因为Servlet可以去依赖或反向通过JNDI的方式得到外部的一些资源包括DataSource或相关EJB组件,像Spring Framework或Peak Container的依赖注入框架也可以帮助实现我们的IoC。

如再扩展到反转控制,消息也算。

  • 996面试题 - 依赖查找和依赖注入的区别?

答:依赖查找是主动或手动的依赖查找方式,通常需要依赖容器或标准API实现。而依赖注入则是手动或自动依赖绑定的方式,无需依赖特定的容器和API。

  • 劝退面试题 - Spring作为IoC容器有什么优势?

答:

  • 典型的IoC管理,依赖查找和依赖注入
  • AOP抽象
  • 事务抽象
  • 事件机制
  • SPI扩展
  • 强大的第三方整合
  • 易测试性
  • 更好的面向对象
上一篇:Angular依赖注入笔记


下一篇:[ .NET依赖项注入] Dependency Injection in.NET - DI catalog [36]