SpringDI和IOC(1.1版本)

Posted 霏ིྀ宇ིྀ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringDI和IOC(1.1版本)相关的知识,希望对你有一定的参考价值。

SpringDI和IOC

SpringDI和IOC

IOC(控制反转)

IOC不是一种技术,主要是一种设计思想。在项目中,传统创建方法是new一个对象,但这样会使得对象间的耦合度增加。
Spring将所有的对象都登机在Spring容器中,并且在系统运行适当的时候通过DI注入到对象当中。
控制反转就是将对象的注册从对象中创建 反转为 Spring统一注册。

IOC:控制反转,由Spring容器管理bean的整个生命周期。通过反射实现对其他对象的控制,包括初始化、创建、销毁等,解放手动创建对象的过程,同时降低类之间的耦合度。

IOC的好处:降低了类之间的耦合,对象创建和初始化交给Spring容器管理,在需要的时候只需向容器进行申请。

IOC底层原理

xml配置文件、工厂模式、反射

IOC的优点

集中管理对象、方便维护 、降低耦合度

IOC和DI的区别

IOC和DI是从不同的角度描述的同一件事IOC是从容器的角度描述,而DI是从应用程序的角度来描述,也可以这样说,IOC是依赖倒置原则的设计思想,而 DI是具体的实现方式(没有DI在Spring中你就拿不到对象。

实验IOC功能(配置文件版)

核心的四个spring的jar包的引入

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4STopYjF-1659016554885)(C:\\Users\\飞\\AppData\\Roaming\\Typora\\typora-user-images\\image-20220728155752438.png)]

IOC容器的配置文件的编写:

即xml文件的编写,根节点,里面是多个,官网上有最小配置的写法。在spring.io进到文档输“”搜索即可。

基于 XML 的配置元数据的基本结构:

<?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
        https://www.springframework.org/schema/beans/spring-beans-4.0.xsd">

    <bean id="..." class="...">  
        <!-- collaborators and configuration for this bean go here -->
    </bean>

    <bean id="..." class="...">
        <!-- collaborators and configuration for this bean go here -->
    </bean>

    <!-- more bean definitions go here -->

</beans>

创建容器BeanFactory

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fSJo5gbR-1659016554886)(C:\\Users\\飞\\AppData\\Roaming\\Typora\\typora-user-images\\image-20220728161104871.png)]

ApplicationContext 允许上下文嵌套,通过保持父上下文可以维持一个上下文体系。对于 Bean 的查找 可以在这个上下文体系中发生,首先检查当前上下文,其次是父上下文,逐级向上,这样为不同的 Spring 应用提供了一个共享的 Bean 定义环境。

  1. ClassPathXmlApplicationContext :xml文件放在class路径中。上下文实例化方式。【强烈推荐】

  2. FileSystemXmlApplicationContext :xml文件放在WEB-INF中,用时可写成磁盘路径

  3. 使用系统路径的方式。 涉及FileSystemResource类

  4. 使用ClassPath查找的方式。涉及ClassPathResource类

 //创建容器方式创建容器BeanFactory
        AbstractApplicationContext context  = new ClassPathXmlApplicationContext("application.context.xml");
         BeanFactory context  = new FileSystemXmlApplicationContext("E:\\\\HQYJ\\\\studyIOC\\\\src\\\\application.context.xml");
       BeanFactory context = new XmlBeanFactory(new FileSystemResource("E:\\\\HQYJ\\\\studyIOC\\\\src\\\\application.context.xml"));

从容器中查找/取bean对象

语法:容器.getBean(selector);

selector一般可以是 (1)字符串:按id或name,(2)Class 按类型(即写法是类型名.class)

 字符串:按id或name,
Student student = (Student) context.getBean("fs");//object
Class 按类型(即写法是类型名.class)
Student student2=context.getBean(Student.class);

spring注入的基本语法如下:

<bean id="被注入的类的beanId" class="包名.类名" />
   <bean id="beanId" class="包名.类名">
          <property name="被注入的bean的名字" ref="被注入的类的beanId"></property>
     </bean>

创建bean的三种方式

spring bean中的id与name的区别:

  • 因name可以用的写法更多就更宽松,所以标签多用name属性。

  • id取值要求严格些,必须满足XML的命名规范。id是唯一的,配置文件中不允许出现两个id相同的。

第一种方式:使用默认构造函数创建:

  <bean name="s" class="com.qq.model.Student"/>

第二种方法:使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)

<bean id="maker" class="com.qq.model.StudentMaker"/>
<bean name="ms" factory-bean="maker" factory-method="make"/>

bean对象创建个数

即scope属性可以是

  1. **scope=“singleton” :单例 **
<bean id="c1" class="com.qq.model.Car" scope="singleton" >
    <property name="brand" value="宝马"/>
    <property name="color" value="红色"/>
</bean>
  1. scope=“prototype”:多个
 <bean name="fs" class="com.qq.model.StudentFactory" factory-method="produce" lazy-init="true"/>
延迟创建
单例情形下,也可以设置成“延迟创建”模式。用lazy-init="true"。
多例情形下,本身就是延迟创建的。
  1. request 一个request范围内,是单例。不常用。

  2. session一个request范围内,是单例。不常用。

对象什么时候创建

多例是对象要用的时候才会创建Bean。即第一次调getBean()时,才创建对象。

单例是容器启动后立即创建Bean 。即如当new ClassPathXmlApplicationContext()时就要创建。

bean对象的初始化和销毁

可以专门给bean设置初始化和销毁的方法,用init-method属性和destroy-method属性来设置。

由于一般观察不到destroy- mothod方法被调用,则可主动调容器的destroy()或close()方法就行。

但是AbstractApplicationContext以及它的继承者才含有destroy()方法或close()方法。

<!--    init-method="init" destroy-method="destroy"-->

Bean对象创建的方式(调用工厂创建)

StudentFactory:(静态工厂)

//静态工厂的静态方法创建bean
    public  static Student produce()
        return new Student(10,"aaa",100);
    
    public Student make()
        return new Student(11,"aaa",100);
    

application.context.xml:

<bean name="fs" class="com.qq.model.StudentFactory" factory-method="produce"/>

StudentFactory:(实例工厂)

//实例工厂创建bean
class  StudentMaker
   public Student make()
       return new Student(11,"aaa",100);
   

application.context.xml:

<!--&lt;!&ndash;    实例工厂创建bean&ndash;&gt;-->
   <bean id="maker" class="com.qq.model.StudentMaker"/>
  <bean name="ms" factory-bean="maker" factory-method="make"/>

DI(依赖注入)

Dependency Injection。它是 spring 核心 ioc 的具体实现。
我们的程序在编写时,通过控制反转,把对象的创建交给了 spring,但是代码中不可能出现没有依赖的情况。ioc 解耦只是降低他们的依赖关系,但不会消除。例如:我们的业务层仍会调用持久层的方法。
那这种业务层和持久层的依赖关系,在使用 spring 之后,就让 spring 来维护了。
简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取。

依赖注入的原理

所谓依赖注入,即在运行期由容器将依赖关系注入到组件之中。
讲的通俗点,就是在运行期,由Spring根据配置文件,将其他对象的引用通过组件的提供的setter方法进行设定。
Spring 大量引入了Java 的Reflection机制,通过动态调用的方式避免硬编码方式的约束,并在此基础上建立了其核心组件BeanFactory,以此作为其依赖注入机制的实现基础。

注入的数据类型

  • 基本类型和String
  • 其他bean类型(在配置文件中或者注解配置过的bean)
  • 复杂类型/集合类型

注入方式

  • Set方法注入

    利用标签注入属性,通过name属性指定属性名,使用value属性或ref属性

    value属性注入 值类型 ,即一般数据类型或字符串

    ref属性注入 引用类型,即使用另外的一个对象

    Student类:

    package com.qq.model;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.beans.factory.annotation.Required;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    
    import javax.annotation.Resource;
    import java.util.Arrays;
    import java.util.Map;
    import java.util.Properties;
    
    /**
     * @description:com.qq.model_studyIOC
     * @author: 霏宇
     * @time: 2022/7/26,11:41
     */
    
    public class Student 
      
        private int id;
    
        private String name;
    
        private int age;
    
        
    
        public Student() 
            System.out.println("无参构造方法");
        
    
        public String getName() 
            return name;
        
    
        public Student(int id, String name, int age) 
            this.id = id;
            this.name = name;
            this.age = age;
           
        
    
        @Override
        public String toString() 
            return "Student" +
                    "id=" + id +
                    ", name='" + name + '\\'' +
                    ", age=" + age
                    '';
        
    
    
    

    在Spring的配置文件中声明需要添加到容器中的对象:

        <bean name="s1" class="com.qq.model.Student">
           <property name="id" value="1"/>
           <property name="name" value="成杨杰"/>
           <property name="age" value="10"/>
    
        </bean>
    
  • 构造方法注入(有参或无参)
    Student类:

    package com.qq.model;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.beans.factory.annotation.Required;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    
    import javax.annotation.Resource;
    import java.util.Arrays;
    import java.util.Map;
    import java.util.Properties;
    
    /**
     * @description:com.qq.model_studyIOC
     * @author: 霏宇
     * @time: 2022/7/26,11:41
     */
    @Component
    public class Student 
    
        private int id;
    
        private String name;
    
        private int age;
    
    
        public Student() 
            System.out.println("无参构造方法");
        
    
        public String getName() 
            return name;
        
    
        public Student(int id, String name, int age, Car car) 
            this.id = id;
            this.name = name;
            this.age = age;
            this.car = car;
        
    
      
    
    
    

    在Spring的配置文件中声明需要添加到容器中的对象:

     <bean name="s1" class="com.qq.model.Student"></bean>
    
  • 有参构造方法注入

    在Spring的配置文件中声明需要添加到容器中的对象:

        <!-- 有参构造注入 -->
      <bean name="s2" class="com.qq.model.Student">
           <constructor-arg name="id" value="2" />
          <constructor-arg name="name" value="sb"/>
          <constructor-arg name="age" value="18" />
      </bean>
    
    
  • p名称空间属性注入(spring4推出)

    • 写法 :
      普通属性:p:属性名=“值”
      对象属性:p:属性名-ref=“值”

    • 步骤:

      • 加入p名称空间:

        <?xml version="1.0" encoding="UTF-8" ?>
        <beans xmlns="http://www.springframework.org/schema/beans"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        
               xmlns:p="http://www.springframework.org/schema/p"
               xsi:schemaLocation="http://www.springframework.org/schema/beans
                https://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
        
        主要:xmlns:p="http://www.springframework.org/schema/p" 
        
      • 书写配置,使用p:属性 进行注入

        形式有
        (1)  p:属性名="值"		,这用于值类型。
        (2)  p:属性名-ref="引用对象的名字"    ,这用于引用类型。
        <bean id="c1" class="com.qq.model.Car" p:brand="宝马" p:color="黑色">
        

​ 注意!在使用p名称空间时,Bean不能以构造方法进行,需使用set方法进行。

  • SpEL属性注入(表达式注入)
    使用#号,而不是$。可以用于把另外的一个bean对象的属性值拿来用,相当方便。

       <bean id="c1" class="com.qq.model.Car" >
           <property name="brand" value="宝马"/>
           <property name="color" value="红色"/>
       </bean>
        <bean name="s1" class="com.qq.model.Student">
            <property name="id" value="1"/>
            <property name="name" value="c1.name"/>
            <property name="age" value="10"/>
            <property name="car" ref="c1"/>
    

Spring用注解的方式 配置bean和 依赖注入

  1. 注解式依赖注入 必须要使用aop包,所以必须导入如spring-aop-4.3.4.RELEASE。

  2. 添加context命名空间,以便能够在编辑xml文件的时候有提示。

  3. 在xml文件中设置要扫描的包

<?xml version="1.0" encoding="UTF-8" ?>
<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-4.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd

">


    <context:annotation-config/>
    <context:component-scan base-package="com.qq.model"/>
<!--    <bean name="c1" class="com.qq.model.Car">-->
<!--        <property name="brand" value="奔驰"/>-->
<!--        <property name="color" value="白色"/>-->
<!--    </bean>-->
<!--    <bean  name="c2" class="com.qq.model.Car">-->
<!--        <property name="brand" value="红旗"/>-->
<!--        <property name="color" value="黑色"/>-->
<!--    </bean>-->
</beans>

作为bean的类用@Component标注。相当于原先在xml 里面配置的节点。实际上,若混合用 注解和xml中的也行

编写的两个类Student和Car,其中Person依赖于Car:

Student

package com.qq.model;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Map;
import java.util.Properties;

/**
 * @description:com.qq.model_studyIOC
 * @author: 霏宇
 * @time: 2022/7/26,11:41
 */
@Component(s1)
public class Student 
    @Value("1")
    private int id;
    @Value("Tom")
    private String name;
    @Value("10")
    private int age;
    @Resource(name="c2") //@Resource可 注入另外一个对象引用,相当于xml里面的ref
    //@Autowired
    //@Qualifier(value = "c2")
    private  Car car;   //@Resource 根据类型注入 根据name指定资源 //@Autowired自动注入根据类型

    @Autowired
    private Vehicle vehicle;

     public void work()
        vehicle.go();
    

   注意细节,阿里架构师一文详解SpringDI的四种依赖注入方式

04-Spring01-IOC

sping IOC和DI 你应该知道事情1

Spring IoC 依赖注入的方法大全

模拟IOC简易扫描器

新手学习Spring IOC控制反转和DI依赖转入总结