ioc与依赖注入

IOC就是一个Spring特有的,用来装类对象的,就是我们用Spring框架时,不需要new对象了,不过我们需要让我们的Spring知道我们写了哪些配置和需要用什么,所以这时我们就要引用Spring的注解或者在配置xml文件上配置我们的类配置,就是在我们自己写的类上加上@Component、@Controller、@Service、@Repository等等这些让我们的Spring知道我们等下要调用有哪些类,让它先准备准备,等下我们需要用了,就getBean或者通过@Autowrite、@Resource来取就行了,给个生活比喻吧,我们就是少爷,IOC是一个管家,我们的类是我们努力的家产,但我的东西太多了,平时要用的时候还要自己一个一个的去拿,这时很容易把自己“累趴”,在Java中我们所说的就是效率太低,和耦合度太高了,这时我们有钱以后肯定想生活更加好,更加方便所以这时就去请人过家要就行了,来帮我们打理家常等这不,IOC管家就来了吗,从此我们在编程时需要什么就直接向管家要就行了,不过你要确定你自己的东西是存在的,而且管家已经知道了才行,不然你又要停下来慢慢的找你的“异常”了。

举个例子就是 spring帮我们管理准备了了一堆我们需要的 对象(bean对象)
在这里插入图片描述

依赖注入

上面我们提到了 用getBean或者通过@Autowrite、@Resource

这里我说一下自己理解的@Autowrite

spring依赖注入 分为三种 分别是

构造方法注入(Construct注入)

,setter注入,

基于注解的注入(接口注入)

如果想看用注解依赖注入 下面可以跳过

·使用属性的setter方法注入 ,这是最常用的方式;
·使用构造器注入;
·使用Filed注入(用于注解方式)。

1.使用属性注入

     属性注入即通过setXxx()方法注入Bean的属性值或依赖对象,由于属性注入方式具有可选择性和灵活性高的优点,因此属性注入是实际应用中最常采用的注入方式。

<bean id=”……” class=”……”>  
    <property name=”属性1” value=”……”/>  
    <property name=”属性2” value=”……”/>  
    ……  
</bean>  

      属性注入要求Bean提供一个默认的构造函数,并为需要注入的属性提供对应的Setter方法。Spring先调用Bean的默认构造函数实例化Bean对象,然后通过反射的方式调用Setter方法注入属性值。来看一个简单的例子。

package com.spring.model;

public class Car {
    
    private int maxSpeed;
    private String brand;
    private double price;
    
    public int getMaxSpeed() {
        return maxSpeed;
    }
    //一定要写被注入对象的set方法
    public void setMaxSpeed(int maxSpeed) {
        this.maxSpeed = maxSpeed;
    }
    public String getBrand() {
        return brand;
    }
    public void setBrand(String brand) {
        this.brand = brand;
    }
    public double getPrice() {
        return price;
    }
    public void setPrice(double price) {
        this.price = price;
    }
    
    public void run(){
        System.out.println("brand:"+brand+",maxSpeed:"+maxSpeed+",price:"+price);
    }
}

     Car类中定义了3个属性,并分别提供了对应的Setter方法。(注:默认构造函数是不带参的构造函数。Java语言规定如果类中没有定义任何构造函数,则JVM自动为其生成一个默认的构造函数。反之,如果类中显示定义了构造函数,则JVM不会为其生成默认的构造函数。所以假设Car类中显示定义了一个带参的构造函数,如public Car(String brand),则需要同时提供一个默认构造函数public Car(),否则使用属性注入时将抛出异常。)
下面在Spring配置文件中对Car进行属性注入:

<!-- 属性注入 -->
<bean id="car" class="com.spring.model.Car">  
    <property name="maxSpeed" value="200"></property>
    <property name="brand" value="红旗CA72"></property>  
    <property name="price" value="200000.00"></property>
</bean>

     在上述代码中配置了一个Bean,并为该Bean的3个属性提供了属性值。具体来说,Bean的每一个属性对应一个<property>标签,name为属性的名称,在Bean实现类中拥有与其对应的Setter方法:maxSpeed对应setMaxSpeed(),brand对应setBrand()。
     需要指出的是:Spring只会检查Bean中是否有对应的Setter方法,至于Bean中是否有对应的属性变量则不做要求。例如配置文件中<property name="brand"/>的属性配置项仅要求Car类中拥有setBrand()方法,但Car类不一定要拥有brand成员变量。

测试方法:

/**
 * 属性注入
 */
@Test
public void test(){
    //读取配置文件
    ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
    //获取bean的实例
    Car car=(Car) ctx.getBean("car");
    car.run();
}

 2.构造函数注入

构造函数注入是除属性注入之外的另一种常用的注入方式,它保证一些必要的属性在Bean实例化时就得到设置,并且确保了Bean实例在实例化后就可以使用。
使用方式:
第一,在类中,不用为属性设置setter方法,但是需要生成该类带参的构造方法。
第二,在配置文件中配置该类的bean,并配置构造器,在配置构造器中用到了<constructor-arg>节点,该节点有四个属性:
· index是索引,指定注入的属性,从0开始;
· type是指该属性所对应的类型;
· ref 是指引用的依赖对象;
· value 当注入的不是依赖对象,而是基本数据类型时,就用value;

(1)按类型匹配入参

      如果任何可用的Car对象都必须提供maxSpeed、brand和price的值,使用属性注入方式只能人为在配置时提供保证,而无法在语法级提供保证,这时通过构造函数注入就可以很好地满足这一要求。使用构造函数注入的前提是Bean必须提供带参的构造函数,下面为Car提供一个可设置maxSpeed、brand和price属性的构造函数。

package com.spring.model;

public class Car {
    
    private int maxSpeed;
    private String brand;
    private double price;
    
    //带参构造方法
    public Car(int maxSpeed,String brand, double price){
        this.maxSpeed=maxSpeed;
        this.brand=brand;
        this.price=price;
    }
    
    public void run(){
        System.out.println("brand:"+brand+",maxSpeed:"+maxSpeed+",price:"+price);
    }
}

构造函数注入的配置方式和属性注入方式的配置有所不同,在spring配置文件中使用构造函数注入装配这个Car Bean。

<!-- 构造函数注入(按类型匹配) -->
<bean id="car1" class="com.spring.model.Car">  
    <constructor-arg type="int" value="300"></constructor-arg>
    <constructor-arg type="java.lang.String" value="宝马"></constructor-arg>
    <constructor-arg type="double" value="300000.00"></constructor-arg>
</bean>

在<constructor-arg>的元素中有一个type属性,它表示构造函数中参数的类型,为spring提供了判断配置项和构造函数入参对应关系的“信息”。

(2)按索引匹配入参

      我们知道,Java语言通过入参的类型及顺序区分不同的重载方法,对于上面代码中的Car类,Spring仅通过type属性指定的参数类型就可以知道“宝马”对应String类型的brand入参,而“300000.00”对应double类型的price入参。但是,如果Car构造函数3个入参的类型相同,仅通过type就无法确定对应关系了,这时需要通过入参索引的方式进行确定。
为了更好地演示按索引匹配入参的配置方式,特意对Car构造函数进行一下调整。

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

brand和corp的入参类型都是String,所以String将无法确定type为String的<constructor-arg>到底对应的是brand还是corp。但是,通过显示指定参数的索引能够消除这种不确定性,如下所示。

<!-- 构造函数注入(按索引匹配) -->
<bean id="car2" class="com.spring.model.Car"> 
    <!-- 注意索引从0开始 --> 
    <constructor-arg index="0" value="宝马"></constructor-arg>
    <constructor-arg index="1" value="中国一汽"></constructor-arg>
    <constructor-arg index="2" value="300000.00"></constructor-arg>
</bean>

构造函数第一个参数索引为0,第二个为1,以此类推,因此很容易知道“宝马”对应brand入参,而“中国一汽”对应corp入参。

(3)联合使用类型和索引匹配入参
     有时需要联合使用type和index才能确定匹配项和构造函数入参的对应关系,看下面的代码。

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

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

     这里,Car拥有两个重载的构造函数,它们都有三个入参。针对这种情况,按照入参索引的配置方式又难以满足要求了,这时需要联合使用<constructor-arg>的type和index才能解决问题,看下面代码。

<!-- 构造函数注入(通过入参类型和位置索引确定对应关系) -->
<!-- 对应public Car(String brand, String corp,int maxSpeed)构造函数 -->
<bean id="car3" class="com.spring.model.Car">  
    <constructor-arg index="0" type="java.lang.String" value="奔驰"></constructor-arg>
    <constructor-arg index="1" type="java.lang.String" value="中国一汽"></constructor-arg>
    <constructor-arg index="2" type="int" value="200"></constructor-arg>
</bean>

      对于上面的两个构造函数,如果仅通过index进行配置,Spring将无法确定第3个入参配置项究竟是对应int的maxSpeed还是double的price,采用索引匹配时,真正引起歧义的地方在于第3个入参,因此仅需要明确指定第3个入参的类型就可以取消歧义了。所以在上面的代码中,第1个和第2个<constructor-arg>元素的type属性可以去除。
      对于由于参数数目相同而类型不同所引起的潜在配置歧义问题,Spring容器可以正确启动且不会给出报错信息,它将随机采用一个匹配的构造函数实例化Bean,而被选择的构造函数可能并不是用户所希望的。因此,必须特别谨慎,以避免潜在的错误。

 3.使用字段(Filed)注入(用于注解方式)

除了上面讲到的使用属性的setter方法或使用构造器方法来注入依赖对象,还有一种注入依赖对象的方法,就是使用注解。

来看一个例子,首先不使用注解的方式。

新建一个业务接口:

package com.spring.service;

public interface ICommonService {
    
    public void add();
}

实现类:

package com.spring.service.impl;

import com.spring.dao.ICommonDao;
import com.spring.service.ICommonService;

public class CommonServiceImpl implements ICommonService{
    
    private ICommonDao commonDao;
    
    // 依赖注入DAO组件所需的setter方法
    public void setCommonDao(ICommonDao commonDao) {
        this.commonDao = commonDao;
    }
    
    public void add(){
        commonDao.add();
    }
}

dao层接口:

package com.spring.dao;

public interface ICommonDao {
    public void add();
}

实现类:

package com.spring.dao.impl;

import com.spring.dao.ICommonDao;

public class CommonDaoImpl implements ICommonDao{
    
    public void add(){
        System.out.println("enter add!");
    }
}

配置文件:

<bean id="commonDao" class="com.spring.dao.impl.CommonDaoImpl"></bean>
<bean id="commonService" class="com.spring.service.impl.CommonServiceImpl">
    <!-- 注入持久化访问所需的DAO组件 -->
    <property name="commonDao" ref="commonDao"/>
</bean>

这里是注解注入     看看我我是注解注入!!!

看下一篇把 我这里暂时不想搞了

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot是基于Spring Framework的,其中最重要的一个概念就是IOC(Inversion of Control,控制反转)和依赖注入(Dependency Injection,DI)。 IOC是一种设计模式,它的核心思想是将对象的创建和对象之间的依赖关系的维护交给一个容器来管理,而不是由应用程序自己去管理。在Spring Boot中,IOC容器负责管理应用程序中的对象,应用程序只需要定义对象的类型和依赖关系,容器就可以自动创建和管理这些对象,从而减少了应用程序的耦合度和代码的复杂度。 依赖注入IOC的一种实现方式,它通过将对象的依赖关系注入到对象中,来解决对象之间的依赖关系问题。在Spring Boot中,依赖注入可以通过构造函数注入、Setter方法注入、注解注入等方式实现。 构造函数注入是通过在对象的构造函数中定义依赖关系的方式实现的,Spring Boot会自动调用构造函数来创建对象,并将依赖关系注入到对象中。 Setter方法注入是通过在对象的Setter方法中定义依赖关系的方式实现的,Spring Boot会自动调用Setter方法来设置对象的依赖关系。 注解注入是通过在对象的属性或方法上添加注解的方式实现的,Spring Boot会自动扫描应用程序中的注解,并自动将依赖关系注入到对象中。 总之,IOC依赖注入Spring Boot的核心思想,它们可以帮助我们更加高效地管理和维护应用程序中的对象和依赖关系,从而提高应用程序的可维护性和可扩展性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值