【Spring框架】Spring DI介绍


DI简介

DI-Dependency Injection 即“依赖注入”,组件之间的依赖关系由容器在运行时决定,即由容器动态的为某个依赖冠以注入到组件中

关键点:谁依赖谁?为什么需要依赖?谁注入谁?注入了什么?

  • 容器:IOC 组件(某一个特定的类:例如:UserService)
  • 资源(组件依赖的内容:例如:mailService)

————————————————————————————

  • 谁依赖于谁:应用程序依赖于IOC容器
  • 为什么需要依赖:应用程序需要IOC容器提供组件需要的外部资源
  • 谁注入谁:IOC容器注入应用程序需要的资源,组件依赖的资源
  • 注入了什么:注入了某个对象所需要的外部资源(包括对象,常量数据,资源)

依赖注入的方式:

  • 基于配置的形式注入依赖
  • 基于注解的形式注入依赖

DI的注入方式

1、基于XML配置文件的注入

(1)基于有参构造函数注入依赖

给定对象User,并给定其有参构造函数:

public class User12 {
    
    
    private Integer id;
    private String name;
    private String passwd;
    private String address;
//    有参构造函数
    public User12(Integer id, String name, String passwd, String address) {
    
    
        this.id = id;
        this.name = name;
        this.passwd = passwd;
        this.address = address;
    }
}

配置中通过构造函数来注入依赖如下:

<!--基于XML形式的依赖注入:有参构造函数-->
<bean id="user" class="com.tulun.bean.User12">
    <!--注入属性-->
    <constructor-arg name="id"  value="1"/>
    <constructor-arg name="name"  value="bob"/>
    <constructor-arg name="passwd"  value="passwd"/>
    <constructor-arg name="address" value="xi'an"/>
</bean>

(2)基于set方法注入依赖

对应的user类提供set方法:

public class User12 {
    
    
    private Integer id;
    private String name;
    private String passwd;
    private String address;
    public User12() {
    
    }
    public void setName(String name) {
    
    
        this.name = name;
    }

在配置文件中用到了property标签:

<!--基于XML形式的依赖注入:set方法-->
<bean id="user1" class="com.tulun.bean.User12">
    <property name="name"  value="luky"/>
    <property name="person" ref="person"/>
</bean>

通过set方法注入依赖使用 < property > 标签,name属性对应的是类中属性名 value对应是赋予的值(只针对基本类型,作为String) 自定类型的注入使用的是ref标签

注入数据处理基本类型,自定义类型,Spring中还支持List、map、set、array等类型的数据注入
例如:

<!--注入list类型-->
<property name="ls">
    <list>
        <value>12</value>
        <value>13</value>
    </list>
</property>
<!--注入map类型数据-->
<property name="ms">
    <map>
        <entry key=" " value=""/>
        <entry key=" " value=""/>
    </map>
</property>

2、基于注解的注入

  • @Value:注入普通形式的依赖;
  • @Resource:注入对象类型;
  • @Autowired:注入对象类型;

使用注解方式注入依赖前提是Bean的装配支持注解扫描

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!--开启注解扫描: base-package(必填)指令包路径: 会扫描类方法、属性上是否有注解-->
    <context:component-scan base-package="com.tulun.bean"></context:component-scan>

    <!--扫描属性上面的注解(不建议使用)-->
    <context:annotation-config></context:annotation-config>
</beans>

@Value注解


@Component(value = "user")
public class User {
    
    
    @Value("1")
    private String id;
    
    @Value("张三")
    private String name;
    
}
public class App{
    
    
    public static void main( String[] args ){
    
    
        //获取IOC的容器
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //通过容器来获取当前的对象
        User user = (User) applicationContext.getBean("user");
        System.out.println(user);
    }
}

在这里插入图片描述

@Autowired注解

@Component(value = "person")
public class Person {
    
    
    //自定义类型属性
    //和@Resource功能一样
    @Autowired
    private User user;

}
public class App{
    
    
    public static void main( String[] args ){
    
    
        //获取IOC的容器
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //通过容器来获取当前的对象
        Person person = (Person)applicationContext.getBean("person");
        System.out.println(person);
    }
}

在这里插入图片描述
高频问点:@Resource和@Autowired的区别?

@Resource@Autowired都是用来做bean的注入时使用的,@Resource@Autowired在有时是可以互相替换换使用的,但是有的时候是不可以的?

  • 共同点:
    @Resource@Autowired都作为bean的注入使用的,在接口仅有一个实现类时,两个注解的修饰效果相同,可以相互替换
  • 不同点:
  1. @Resource是Java自己的注解
  2. @Resource注解有两个属性比较重要,一个是name,一个是type,Spring中使用name属性解析为bean的名称,使用type时解析为bean的类型,如果没有给定属性值,Spring的反射机制通过byName来自动注入属性
  3. @Autowired是Spring提供的注解,在Spring2.5版本后引入的只根据type去进行注入,不用name ,如果涉及到type无法识别注入对象时,仅使用@Autowired是无法完成注入的,需要借助其他的注解一块才能完成

依赖的解析过程

在Spring的依赖的解析过程:

  • ApplicationContext通过配置的元数据来创建和初始化,这些元数据描述了所有的bean,元数据的信息是可以通过注解,xml或者是Java代码来描述
  • 对于每一个bean,他的依赖用属性、构造函数或者是静态工厂方法等形式来表达,bean被创建好之后这些依赖会提供给他
  • 每一个属性或者构造方法都要被设置的值的实际定义,或者是对容器中的另一个bean的引用
  • 每个属性或者构造方法的值的实际定义都会转化为当前实例bean的实际的值

在容器创建的过程中,Spring容器会验证每一个bean的配置,在实际创建bean之前,bean的属性不会被设置,单例和被设置为首先加载的bean会在容器初始化后就创建出来,其他的bean只会在需要的时候才会创建,创建bean过程可能会引起一系列的bean被创建,注意:此时依赖之间解析不匹配的问题有可能会出现,即会循环创建有影响的Bean

循环依赖问题:

class User{
    
    
    private Person person;
}
class Person{
    
    
    private User user;
}
  • 此时如果是通过构造方法的方式注入,就有可能造成无法解决的循环依赖。
  • 例如:ClassA需要通过构造方法注入一个ClassB的实例,ClassB同样需要通过构造方法注入ClassA的实例,如果为ClassA和ClassB配置Bean并且相互注入,IOC容器在运行时会发现这个循环引用,并抛出异常:BeanCurrentlyInCreationException

解决途径是:这些类可以通过setter注入,避免使用构造方法注入

猜你喜欢

转载自blog.csdn.net/Super_Powerbank/article/details/113155115
今日推荐