SpringDI和IOC(1.1版本)

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();
    }

   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;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
               ", name='" + name + '\'' +
               ", age=" + age +
               ", car=" + car +
               '}';
    }
}

Car:

package com.qq.model;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @description:com.qq.model_studyIOC
 * @author: 霏宇
 * @time: 2022/7/26,17:10
 */
@Component(name="c2")
public class Car  implements Vehicle{
    @Value("宝马")
    private String brand;
    @Value("红色")
    private String color;

    @Override
    public void go() {
        System.out.println("Car的go..........");

    }

    public Car(String brand, String color) {
        this.brand = brand;
        this.color = color;
    }

    public Car() {
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

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

测试类:

package com;
import com.qq.model.Student;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * @description:com_studyIOC
 * @author: 霏宇
 * @time: 2022/7/26,11:43
 */
public class MyTest1 {
    public static void main(String[] args) {
        //创建容器
        //应用程序上下文
        //BeanFactory,ApplicationContext,AbstractApplicationContext;


        //创建容器方式创建容器BeanFactory
       AbstractApplicationContext context  = new ClassPathXmlApplicationContext("application.context.xml");

        //注解
        Student student = (Student) context.getBean("s1");
        System.out.println(student);
        context.close();


    }
}

@Component系列注解

相当于xml里面的。中文意思“组件”。

这一系列都注在类上,包括以下

  • @Component:最通用的组件,适用于所有组件
  • @Controller:适用于controller层
  • @Repository:适用于持久层(数据库)
  • @Service: 适用于service层(服务)

@Scope注解

它注在@Component系列注解修饰过的类上 才有意义。

其scopeName取值二选一。(其实是因为另外的其它取值特别不常用)

@Scope注解是 Spring IOC 容器中的一个作用域,在 Spring IOC容器中,他用来配置Bean实例的作用域对象。@Scope 具有以下几种作用域:

@Scope注解怎么使用

① 在不指定@Scope的情况下,所有的bean都是单实例的bean,而且是饿汉模式加载(容器启动实例就创建好了)

@Bean 
public Person person() { 
	return new Person(); 
}

②指定@Scope为 prototype 表示为多实例的,而且还是懒汉模式加载(IOC容器启动的时候,并不会创建对象,而是 在第一次使用的时候才会创建)

@Bean 
@Scope(value = "prototype") 
public Person person() { 
	return new Person(); 
}

恶汉/懒汉

  1. 使用singleton单例,采用饿汉加载(容器启动,Bean实例就创建好了)

  2. 使用prototype多例,采用懒汉加载(IOC容器启动的时候,并不会创建对象实例,而是在第一次使用的时候才会创建)

自动装配@AutoWired

修饰成员。它是优先“按类型byType”来查找Bean并注入的

自动装配存在的问题:如果一个被依赖的类型有多个bean都适用,那么选择哪一个bean呢?

在配置文件xml:

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

方案一:联合使用***@Qualifier***来选择。

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;
    @Autowired
    @Qualifier(value = "c2")
   
    private  Car car;   //@Resource 根据类型注入 根据name指定资源 //@Autowired自动注入根据类型

    @Autowired
    private Vehicle vehicle;

     public void work(){
        vehicle.go();
    }

    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;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", car=" + car +
                '}';
    }
}

方案二:使用@Resource注解(它是javax.annotation.Resource;,是java标准的注解,spring实现它了),并使用name属性来选择

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")
    private  Car car;   //@Resource 根据类型注入 根据name指定资源 //@Autowired自动注入根据类型

    @Autowired
    private Vehicle vehicle;

     public void work(){
        vehicle.go();
    }

    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;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", car=" + car +
                '}';
    }
}

初始化方法和销毁方法

public class Person {
	
	public Person() {
		System.out.println("Person构造方法被调用");
	}

	@PostConstruct	//相当于xml配置方式中bean标签的init-mothod属性
	public void init(){
		System.out.println("Person对象初始化");
	}
	
	@PreDestroy	//相当于xml配置方式中bean标签的destroy-mothod属性
	public void destroy(){
		System.out.println("Person对象销毁");
	}
}

配置类,标记了@Configuration,相当于原先的一个xml文件。@bean,相当于一个标签

import com.qq.model.Student;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

/**
 * @description:com.qq.config_studyIOC
 * @author: 霏宇
 * @time: 2022/7/27,13:41
 */
@Configuration
public class MyConfig {
    @Bean
    Student fun(){
        Car car =new Car("红旗","黑色");
        return new Student(1,"成杨杰",17,car);
    }
}

毁方法

public class Person {
	
	public Person() {
		System.out.println("Person构造方法被调用");
	}

	@PostConstruct	//相当于xml配置方式中bean标签的init-mothod属性
	public void init(){
		System.out.println("Person对象初始化");
	}
	
	@PreDestroy	//相当于xml配置方式中bean标签的destroy-mothod属性
	public void destroy(){
		System.out.println("Person对象销毁");
	}
}

配置类,标记了@Configuration,相当于原先的一个xml文件。@bean,相当于一个标签

import com.qq.model.Student;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

/**
 * @description:com.qq.config_studyIOC
 * @author: 霏宇
 * @time: 2022/7/27,13:41
 */
@Configuration
public class MyConfig {
    @Bean
    Student fun(){
        Car car =new Car("红旗","黑色");
        return new Student(1,"成杨杰",17,car);
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值