Spring IOC&DI概述

2020-03-17  本文已影响0人  BlueSkyBlue

IOC(Inversion of Control)

其思想是反转资源获取的方向。传统的资源查找方式要求组件向容器发起请求查找资源。作为回应,容器适时的返回资源。而使用了IOC之后,是容器主动将资源推送给它管理的组件,组件所需要做的则是选择一种合适的方式来接收资源。这种行为也被称为查找的被动形式。

DI(Dependency Injection)

IOC的另一种表述方式,即组件以一些预先定义好的方式(例如Setter)接收来自容器的资源注入。相比于IOC而言,这种表述更为直接。

通过XML的方式进行IOC有一个缺陷就是必须要有一个无参的构造器。如果要创建的Bean中的构造器是有参的则抛出异常。

DI实例

<bean id="helloWorld" class="com.spring.beans.HelloWorld">
    <property name="name" value="Spring"></property>
</bean>

class: bean的全类名,通过反射的方法在IOC容器中创建bean。所以要求Bean中必须有无参构造函数。
id: 标识容器中的bean, id唯一。

Spring容器

ApplicationContext代表IOC容器。但是它实际上是一个接口。

在Spring IOC容器读取Bean,配置Bean,创建Bean实例之前必须要对它进行实例化。只有在容器实例化之后才可以从IOC容器中获取Bean实例并使用。

Spring提供了两种类型的IOC容器的实现:

BeanFactory是Spring框架的基础设施,面向Spring本身。ApplicationContext面向使用Spring框架的开发者本身。几乎所有的应用场合都使用ApplicationContext而非BeanFactory。

无论使用何种方式,配置文件时都是相同的。

ApplicationContext

ApplicationContext继承关系

ApplicationContext的主要实现类有

ConfigurableApplicationContext扩展于ApplicationContext。新增两个主要的方法refresh()和close()。让ApplicationContext具有启动,关闭和刷新上下文的能力。

ApplicationContext在初始化上下文时就实例化所有的单例的Bean。

WebApplicationContext是专门为Web准备的,它允许从Web根目录的路径中完成初始化的工作。

也可以通过类名来获取Bean,例如

HelloWorld hello2 = applicationContext.getBean(HelloWorld.class);

但是该方法有一个缺陷。就是当IOC容器中配置了两个来自同一个类的bean的时候,系统不知道要创建的是那一个bean就会抛出异常。所以要求IOC容器中只能有一个该类型的bean。

依赖注入的方式

属性注入

通过setter方法注入Bean的属性值或依赖的对象。
属性名注入使用的是<property/>标签,使用name属性指定Bean的属性名称。value属性或<value/>子结点指定属性值。
属性注入是开发中最常用的注入方式。

构造方法注入

通过构造方法注入Bean的属性值或依赖的对象。它保证了Bean实例在实例化之后就可以使用

构造器注入在<constructor-agr>元素里声明属性。<constructor-arg>中没有name属性。

使用构造器注入属性值可以指定参数的位置和参数的类型,以区分重载的构造器。

构造器注入示例

创建一个新的类

public class Car {
    private String brand;
    private String corp;
    private int price;
    private int maxSpeed;

    public Car(String brand, String corp, int price, int maxSpeed) {
        super();
        this.brand = brand;
        this.corp = corp;
        this.price = price;
        this.maxSpeed = maxSpeed;
    }

    @Override
    public String toString() {
        return "Car{" +
                "brand='" + brand + '\'' +
                ", corp='" + corp + '\'' +
                ", price=" + price +
                ", maxSpeed=" + maxSpeed +
                '}';
    }
}

配置文件中注册

<bean id="car" class="com.spring.beans.Car">
    <constructor-arg value="Audi"></constructor-arg>
    <constructor-arg value="Shanghai"></constructor-arg>
    <constructor-arg value="300000"></constructor-arg>
    <constructor-arg value="10000"></constructor-arg>
</bean>

主函数中调用

public static void main(String[] args) {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    Car car = applicationContext.getBean(Car.class);
    System.out.println(car);
}

问题来了?如果类中有两个构造方法,如下所示:

public class Car {
    private String brand;
    private String corp;
    private int price;
    private double maxSpeed;

    public Car(String brand, String corp, int price) {
        super();
        this.brand = brand;
        this.corp = corp;
        this.price = price;
    }

    public Car(String brand, String corp, double maxSpeed) {
        super();
        this.brand = brand;
        this.corp = corp;
        this.maxSpeed = maxSpeed;
    }
...

我们想要使用的是第二个构造函数。此时我们可以在配置文件中指定构造参数的类型。例如

<bean id="car" class="com.spring.beans.Car">
    <constructor-arg value="Audi" type="java.lang.String"></constructor-arg>
    <constructor-arg value="Shanghai" type="java.lang.String"></constructor-arg>
    <constructor-arg value="10000" type="double"></constructor-arg>
</bean>
上一篇下一篇

猜你喜欢

热点阅读