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 定义环境。
-
ClassPathXmlApplicationContext :xml文件放在class路径中。上下文实例化方式。【强烈推荐】
-
FileSystemXmlApplicationContext :xml文件放在WEB-INF中,用时可写成磁盘路径。
-
使用系统路径的方式。 涉及FileSystemResource类
-
使用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属性可以是
- **scope=“singleton” :单例 **
<bean id="c1" class="com.qq.model.Car" scope="singleton" >
<property name="brand" value="宝马"/>
<property name="color" value="红色"/>
</bean>
- scope=“prototype”:多个
<bean name="fs" class="com.qq.model.StudentFactory" factory-method="produce" lazy-init="true"/>
延迟创建
单例情形下,也可以设置成“延迟创建”模式。用lazy-init="true"。
多例情形下,本身就是延迟创建的。
-
request 一个request范围内,是单例。不常用。
-
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:
<!--<!– 实例工厂创建bean–>-->
<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和 依赖注入
-
注解式依赖注入 必须要使用aop包,所以必须导入如spring-aop-4.3.4.RELEASE。
-
添加context命名空间,以便能够在编辑xml文件的时候有提示。
-
在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的四种依赖注入方式