spring学习之IOC和DI

前面我们已经讲过了,通过spring提供的IOC容器,用户可以将对象之间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。那么什么是IOC?

什么是IOC

IOC全称是Inversion of Control,中文名称是反转控制。其核心思想就是反转资源获取的方向。

传统的资源查找方式要求组件向容器发起请求查找资源,然后作为回应,容器返回资源。而应用了IOC之后,则是容器在组件需要资源的时候主动地将资源推送给它管理的组件,而组件要做的就是选择一种合适的方式来接受资源。

那IOC和DI有什么联系呢?

DI

DI全称是Dependency Injection,中文名称是依赖注入。核心思想也就是组件与一些预先定义的方式(如setter方法)接受来自容器的注入,其实它等待本质也就是IOC。

举个栗子

这里写图片描述
传统方式:我们既需要知道某个接口类型,还需要知道有哪些具体实现类,甚至我们还需要知道怎么实现一个具体类。无疑,这种耦合度是最高的。

工厂设计模式:
这里写图片描述

我们只需要知道某个接口类型和绑定某个工厂就好了,耦合度显然降低了很多,但是代码无疑是复杂了。

IOC方式:
这里写图片描述
这是我们的最终目标,站在Service的角度来看,它只需要绑定到IOC容器就可以了,剩下的一切就交给IOC来处理了。

如何使用IOC

IOC的使用主要是Bean的配置,Bean的配置形式有两种:基于XML文件的方式和基于注解的方式。

XML文件配置

bean的配置方式有三种:通过全类名(反射)、通过工厂方法(静态方法&实例工厂方法)、FactoryBean。

全类名反射

全类名反射是通过JAVA的反射机制在IOC容器中创建bean,所以需要一个默认的构造函数,即无参的构造函数。
一个栗子,永远的HelloWord。
配置:

<?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">

    <!-- 配置bean -->
    <bean id="bean" class="com.yixingu.Bean">
        <property name="name" value="spring"></property>
    </bean>
</beans>

其中Bean:

package com.yixingu;

public class Bean {
    private String name;
    public void setName(String name) {
        this.name = name;
    }

    public void hello() {
        System.out.println("hello " + name);
    }

}

使用:

package com.yixingu;

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

public class Main {

    public static void main(String[] args) {
        /*传统方式
        Bean bean = new Bean();
        bean.setName("spring");
        */
        //1.获取ioc容器
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2.获取bean实例
        Bean bean = (Bean) context.getBean("bean");
        //3.调用方法
        bean.hello();
    }
}

说明:在Spring IOC容器通过XML文件读取Bean配置实例之前,必须对IOC容器进行实例化,其中ApplicationContext就是IOC容器。**ApplicationContext在初始化上下文的时候就实例化所有单例的Bean。**Spring框架还提供了另外一种IOC容器的实现方式:BeanFactory。**BeanFactory在实例化容器时并未初始化bean,直到第一次使用bean时才实例化目标bean。**BeanFactory是面向Spring本身的,也就是底层实现,ApplicationContext是面向开发者的。我们几乎都使用ApplicationContext。

ApplicationContext本身是一个借口,我们实例化IOC容器时使用的是它的子类:
这里写图片描述
ConfigurableApplicationContext扩展于ApplicationContext,新增两个主要的方法:refresh()和close(),让ApplicationContext具有启动、刷新和关闭上下文的功能。

依赖注入的方式

相信细心的读者已经发现了,我们并没有调用set方法呀,怎么最终结果却是有值的?其实核心就在XML配置文件中:

<!-- 配置bean -->
    <bean id="bean" class="com.yixingu.Bean">
        <property name="name" value="spring"></property>
    </bean>

这种方式也是我们最常用的——属性注入。属性注入就是根据setter方法为bean注入值,其中property对应bean的属性值。此外,还有构造器注入和工厂方法注入,其中,工厂方法注入使用比较复杂,也用得比较少。

接下来,我们看看构造器注入的实现。
新建Car.java文件:

package com.yixingu;

public class Car {
    private String brand;
    private String crop;
    private int maxSpeed;
    private int price;
    public Car(String brand, String crop, int maxSpeed) {
        super();
        this.brand = brand;
        this.crop = crop;
        this.maxSpeed = maxSpeed;
    }
    @Override
    public String toString() {
        return "Car [brand=" + brand + ", crop=" + crop + ", maxSpeed=" + maxSpeed + ", price=" + price + "]";
    }

}

配置通过构造器Bean:

<!-- 通过构造器注入bean -->
    <bean id="car" class="com.yixingu.Car">
        <constructor-arg value="Audi" index="0"></constructor-arg>
        <constructor-arg value="shanghai" index="1"></constructor-arg>
        <constructor-arg value="250" index="2"></constructor-arg>
    </bean>

但是这种配置方式有一个很明显的缺点,假设Car文件新增一个构造器:

public Car(String brand, String crop, double price) {
        super();
        this.brand = brand;
        this.crop = crop;
        this.price = price;
    }

由于配置文件文件中的第三个参数是int类型的,double类型的属性同样可以使用,这时spring就无法判断你到底是想给哪个赋值了,只会默认给第一个符号条件的构造函数赋值,那么我们该如何解决呢?

我们可以通过指定类型来为我们想要赋值的参数的赋值:

<bean id="car" class="com.yixingu.Car">
        <constructor-arg value="Audi" type="String"></constructor-arg>
        <constructor-arg value="shanghai" type="String"></constructor-arg>
        <constructor-arg value="250" type="double"></constructor-arg>
    </bean>

最后一种工厂方法注入注入方式就不讲了,因为这种方式本身就比较复杂,而且用得极其少。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值