Spring使用 --- 基本概念(一):DI,依赖注入

本文讲述sprint基本概念之一: DI, 即依赖注入。

什么是依赖注入

说类A依赖于类B,最简单的例子是类A有一个类型为类B的成员变量。

依赖注入是指类A不用关心类B对象如何创建,它只知道有一个类B的对象,只需要使用就行了。 这样有几个好处:

  1. 可以很容易替换类B的对象,达到不同的效果
  2. 类A更容易测试。只需要创建一个类B的mock对象即可。
  3. 类A与类B解藕

不使用依赖注入时,类A负责创建类B的对象,写法如下:

class A {
    B b;
    A (){
        // 此处A创建一个B的对象,作为自己的成员变量
        b = new B();
    }
    void foo(){
        b.bar();
    }
}

class B {
    void bar(){
        System.out.println("B bar");
    }
}

其中创建类B对象的代码写死在类A的定义中,很码很僵化。如果想使用B的一个子类对象,除了修改类A的代码,别无它法。

一种更好的方法是通过构造器传入类B的对象,代码如下:

class A {
    B b;
    A (B b){
        this.b = b;
    }
    void foo(){
        b.bar();
    }
}
// B的定义不变

这种方法也叫构造器注入。此时代码灵活了很多。此时类A的代码可以处理所有类B的子类。一般将B定义为接口,实际传入的是一个实现。这也是面向接口编程的一个例子。

Sprint中对于依赖注入实现的效果与构造器注入大致相同,只不过使用xml配置文件来完成将类B的对象装配给类A的对象。依赖注入主要维护对象之前的依赖关系,对象的创建。如果对象a依赖于另一个对象b,则Spring创建对象a时,根据事先定义的依赖规则(一般写在xml文件中),会先创建一个对象b,然后再创建对象a,最后将b装配给对象a。装配的意思是赋值,一般通过调用setter函数。

怎样使用

仍然采用上面的例子,类A,类B的定义如下:

class A {
    B b;
    A (B b){
        this.b = b;
    }
    void foo(){
        b.bar();
    }
}
class B {
    void bar(){
    }
}

再创建一个xml文件,指定类A、B的依赖关系:

<beans>
  <bean id="a" class="A">
    <constructor-arg ref="b"/>
  </bean>
  <bean id="b" class="B">
  </bean>
</beans>

最后在主代码中调用ApplicationContext.getBean("a")函数来获取类A的一个实例:

import org.springframework.context.support.ClassPathXmlApplicationContext;
class Test {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context =
            new ClassPathXmlApplicationContext("a.xml");
        A a = context.getBean("a");
        a.foo();
        context.close();
    }
}

其中ApplicationContext是bean的container,bean是一个符合一定要求的java类。

什么时候使用

只要是有对象依赖的情况下,都可以使用依赖注入来将类之前的依赖也类对象的创建这部分从核心代码里剥离出来,通过srping来管理及实现。感觉实际上是软件模块、组件更细的划分。

任何稍大一些的软件都是由多个类组成,这些类协同共同完成功能(通过组合的方式)。因此在绝大多数项目中都需要使用。

好处

  • 对象之间解藕
  • 可能方便的更改使用哪个依赖对象,只需要修改配置文件就行了
  • 类的测试会方便很多,只要为所有依赖的类创建mock对象即可

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏cnblogs

Javascript的原型继承,说清楚

     一直以来对Javascript的原型、原型链、继承等东西都只是会用和了解,但没有深入去理解这门语言关于继承这方面的本质和特点。闲暇之余做的理解和总...

1649
来自专栏Java 技术分享

SpringMVC(二)

1123
来自专栏JavaEE

做Java开发,你需要了解这些前言

在开发中,我们写的代码肯定是越少越好,代码层次越清晰越好。那么下面就介绍一些可以减少代码量、可以让结构更清晰的好东西。本文涉及vo、dto的使用、全局异常处理、...

803
来自专栏Zephery

2017-03-02学习笔记

知识点 一、static public class Spike { public static void main(String[] args) ...

36210
来自专栏java一日一条

Java集合框架综述

近被陆陆续续问了几遍HashMap的实现,回答的不好,打算复习复习JDK中的集合框架,并尝试分析其源码,这么做一方面是这些类非常实用,掌握其实现能更好的优化我们...

714
来自专栏前端儿

JavaScript 面向对象继承详解

由于js不像java那样是完全面向对象的语言,js是基于对象的,它没有类的概念。所以,要想实现继承,一般都是基于原型链的方式;

501
来自专栏用户画像

C++ 在继承中虚函数、纯虚函数、普通函数,三者的区别

版权声明:本文为博主-姜兴琪原创文章,未经博主允许不得转载。 https://blog.csdn.net/jxq0816/article/details...

333
来自专栏领域驱动设计DDD实战进阶

10-TypeScript中的接口

接口是一种规约的约定,从接口继承的类必须实现接口的约定。在高级开发中,通常接口是用于实现各种设计模式的基础,没有接口,设计模式无从谈起。 定义接口: inter...

2877
来自专栏抠抠空间

面向对象的三大特性

继承 继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类 python中类的继承分为:...

3206
来自专栏机器学习从入门到成神

org.hibernate.hql.ast.QuerySyntaxException is not mapped异常

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_35512245/articl...

732

扫码关注云+社区