zoukankan      html  css  js  c++  java
  • 依赖注入是实现控制反转的方式之一

    https://en.wikipedia.org/wiki/Inversion_of_control

    In software engineeringinversion of control (IoC) is a design principle in which custom-written portions of a computer program receive the flow of control from a generic framework. A software architecture with this design inverts control as compared to traditional procedural programming: in traditional programming, the custom code that expresses the purpose of the program calls into reusable libraries to take care of generic tasks, but with inversion of control, it is the framework that calls into the custom, or task-specific, code.

    Inversion of control is used to increase modularity of the program and make it extensible,[1] and has applications in object-oriented programming and other programming paradigms. The term was popularized by Robert C. Martin and Martin Fowler.

    https://zh.wikipedia.org/wiki/控制反转

    控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。

    技术描述

    Class A中用到了Class B的对象b,一般情况下,需要在A的代码中显式的new一个B的对象。

    采用依赖注入技术之后,A的代码只需要定义一个私有的B对象,不需要直接new来获得这个对象,而是通过相关的容器控制程序来将B对象在外部new出来并注入到A类里的引用中。而具体获取的方法、对象被获取时的状态由配置文件(如XML)来指定。

    实现方法

    实现控制反转主要有两种方式:依赖注入和依赖查找。两者的区别在于,前者是被动的接收对象,在类A的实例创建过程中即创建了依赖的B对象,通过类型或名称来判断将不同的对象注入到不同的属性中,而后者是主动索取相应类型的对象,获得依赖对象的时间也可以在代码中自由控制。

    依赖注入

    依赖注入有如下实现方式:

    • 基于接口。实现特定接口以供外部容器注入所依赖类型的对象。
    • 基于 set 方法。实现特定属性的public set方法,来让外部容器调用传入所依赖类型的对象。
    • 基于构造函数。实现特定参数的构造函数,在新建对象时传入所依赖类型的对象。
    • 基于注解。基于Java的注解功能,在私有变量前加“@Autowired”等注解,不需要显式的定义以上三种代码,便可以让外部容器传入对应的对象。该方案相当于定义了public的set方法,但是因为没有真正的set方法,从而不会为了实现依赖注入导致暴露了不该暴露的接口(因为set方法只想让容器访问来注入而并不希望其他依赖此类的对象访问)。

    依赖查找

    依赖查找更加主动,在需要的时候通过调用框架提供的方法来获取对象,获取时需要提供相关的配置文件路径、key等信息来确定获取对象的状态

    0-暗喻
    我们需要肚子不饿我们要做出来吃的而厨房提供了做吃的的方法,于是为了肚子不饿我们“依赖”厨房
    我们需要有电脑我们要有钱而劳动给了使我们有钱的方法, 于是为了我们有电脑我们“依赖”劳动

    Ci介绍
    目录结构
    实例
    我们要的不是“厨房、劳动”,我们是为了某些结果而“依赖”他们
    需要的是一个结果集,为了得到这个结果集,需要一个方法method,而这个方法在一个class中,故依赖这个class,于是实例化这个class

    https://www.tutorialspoint.com/spring/spring_dependency_injection.htm

    Every Java-based application has a few objects that work together to present what the end-user sees as a working application. When writing a complex Java application, application classes should be as independent as possible of other Java classes to increase the possibility to reuse these classes and to test them independently of other classes while unit testing. Dependency Injection (or sometime called wiring) helps in gluing these classes together and at the same time keeping them independent.

    Consider you have an application which has a text editor component and you want to provide a spell check. Your standard code would look something like this −

    public class TextEditor {
       private SpellChecker spellChecker;
       
       public TextEditor() {
          spellChecker = new SpellChecker();
       }
    }

    What we've done here is, create a dependency between the TextEditor and the SpellChecker. In an inversion of control scenario, we would instead do something like this −

    public class TextEditor {
       private SpellChecker spellChecker;
       
       public TextEditor(SpellChecker spellChecker) {
          this.spellChecker = spellChecker;
       }
    }

    Here, the TextEditor should not worry about SpellChecker implementation. The SpellChecker will be implemented independently and will be provided to the TextEditor at the time of TextEditor instantiation. This entire procedure is controlled by the Spring Framework.

    Here, we have removed total control from the TextEditor and kept it somewhere else (i.e. XML configuration file) and the dependency (i.e. class SpellChecker) is being injected into the class TextEditor through a Class Constructor. Thus the flow of control has been "inverted" by Dependency Injection (DI) because you have effectively delegated dependances to some external system.

    The second method of injecting dependency is through Setter Methods of the TextEditor class where we will create a SpellChecker instance. This instance will be used to call setter methods to initialize TextEditor's properties.

    Thus, DI exists in two major variants and the following two sub-chapters will cover both of them with examples −

    Sr.No.Dependency Injection Type & Description
    1 Constructor-based dependency injection

    Constructor-based DI is accomplished when the container invokes a class constructor with a number of arguments, each representing a dependency on the other class.

    2 Setter-based dependency injection

    Setter-based DI is accomplished by the container calling setter methods on your beans after invoking a no-argument constructor or no-argument static factory method to instantiate your bean.

    You can mix both, Constructor-based and Setter-based DI but it is a good rule of thumb to use constructor arguments for mandatory dependencies and setters for optional dependencies.

    The code is cleaner with the DI principle and decoupling is more effective when objects are provided with their dependencies. The object does not look up its dependencies and does not know the location or class of the dependencies, rather everything is taken care by the Spring Framework.

    springsrcmain esourceseans.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- Definition for textEditor bean using inner bean -->
    <bean id="textEditor" class="com.tutorialspoint.TextEditor">
    <property name="spellChecker">
    <bean id="spellChecker" class="com.tutorialspoint.SpellChecker"></bean>
    </property>
    </bean>

    </beans>

    springsrcmainjavacom utorialspointMainApp.java
    package com.tutorialspoint;

    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;

    public class MainApp {
    public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
    TextEditor te = (TextEditor) context.getBean("textEditor");
    te.spellCheck();
    }
    }

    D:workspspringsrcmainjavacom utorialspointSpellChecker.java

    package com.tutorialspoint;

    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;

    public class MainApp {
    public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
    TextEditor te = (TextEditor) context.getBean("textEditor");
    te.spellCheck();
    }
    }


    springsrcmainjavacom utorialspointTextEditor.java


    package com.tutorialspoint;

    public class TextEditor {
    private SpellChecker spellChecker;

    // a setter method to inject the dependency.
    // 注释掉,则
    // 十一月 30, 2018 5:26:46 下午 org.springframework.context.support.ClassPathXmlApplicationContext refresh
    // 警告: Exception encountered during context initialization - cancelling refresh attempt
    // org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'textEditor' defined in class path resource [Beans.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'spellChecker' of bean class [com.tutorialspoint.TextEditor]: Bean property 'spellChecker' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
    public void setSpellChecker(SpellChecker spellChecker) {
    System.out.println("Inside setSpellChecker.");
    this.spellChecker = spellChecker;
    }

    // a getter method to return spellChecker
    // 注释掉,未报bug
    // public SpellChecker getSpellChecker() {
    // return spellChecker;
    // }

    public void spellCheck() {
    spellChecker.checkSpelling();

    }
    }







  • 相关阅读:
    JDK框架简析--java.lang包中的基础类库、基础数据类型
    Mahout 模糊kmeans
    使用heartbeat+monit实现主备双热备份系统
    Git版本号控制:Git分支处理
    JAVA线程
    Nginx的特性与核心类别及配置文件和模块详解
    nginx设置反向代理后端jenklins,页面上的js css文件无法加载
    运维的危险命令,用了必死(1)
    xtrabackup备份MySQL
    利用ansible-playbook从测试环境获取tomcat中java项目新版本发布到生产环境
  • 原文地址:https://www.cnblogs.com/rsapaper/p/6625028.html
Copyright © 2011-2022 走看看