IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> IOC容器与DI注入 -> 正文阅读

[Java知识库]IOC容器与DI注入

Spring Core 学习 IOC容器与DI深入理解



前言

Spring Core:

Spring 的核心功能:IOC容器,解决对象创建及依赖关系。

Spring的核心思想之一:Inversion of Control,控制反转 IOC,对象的创建交给外部容器来完成,这个就称之为控制反转。

  • Spring 使用控制反转来实现对象不需要再程序中写死
  • 控制反转解决问题处理问题【把对象交给别人来创建】

对象与对象之间的依赖关系通过 dependency injection 依赖注入解决

  • Spring 使用依赖注入来实现对象直接的依赖关系
  • 在创建完对象之后,对象的依赖关系处理即是依赖注入

??无论是创建对象、处理对象之间的依赖关系、对象创建的时间还是要创建对象的数量,我们都是在Spring 为我们提供的IOC 容器上配置对象的信息即可。IOC的思想最核心的地方在于,资源不由要使用资源的双方管理,而是由不使用资源的第三方来管理,一是可以实现资源的集中管理,二是可以降低使用资源双方的依赖程度,低耦合。

在这里插入图片描述


一、Core模块入门

1. 新建Spring项目

  1. 使用IDEA创建一个maven项目,在pom.xml中引入对应的jar包

??commons-logging-1.1.3.jar 日志、spring-beans-5.2.21.RELEASE.jar bean节点、spring-context-5.2.21.RELEASE.jar spring上下文节点、spring-core-5.2.21.RELEASE.jar spring核心功能、spring-expression-5.2.21.RELEASE.jar spring表达式

  1. 准备Spring的配置文件按

??在resources 目录下创建spring的配置文件,可以直接选择idea 中的选项
在这里插入图片描述

  1. 编写启动类

??在java 文件夹下新建启动类Application,可以通过两种方式得到Spring的 IOC 容器对象:1通过Bean 工厂,BeanFactory;2通过Resource 获取BeanFactory (常用)
在这里插入图片描述

2. IOC容器与对象创建

  1. 获取到了IOC容器,通过IOC容器配置对象

在Spring 中总体来看, 可以通过四种方式来配置对象

  1. 使用XML 文件来配置
  2. 使用注解来配置
  3. 使用JavaConfig 来配置
  4. groovy 脚本DSL

??准备一个User类,先不指定构造方法,在xml中配置

<!--使用bean节点来创建对象, id对象属性标识符, class关联类-->
<bean id="user" class="User"></bean>

通过IOC容器得到无参构造方法对象完成
在这里插入图片描述
Java中几种常用的创建对象方法有:无参构造器创建、有参构造器创建、工厂模式创建(静态方法、非静态方法)

// 创建带参的构造函数
public User(String id, String username) {
    this.id = id;
    this.username = username;
}
<!--xml中也要传入构造函数中对应的参数-->
<bean id="user" class="User">
    <!--通过constructor这个节点来指定构造函数的参数类型、名称、第几个-->
    <constructor-arg index="0" name="id" type="java.lang.String" value="01"></constructor-arg>
    <constructor-arg index="1" name="username" type="java.lang.String" value="zhoukang"></constructor-arg>
</bean>

在这里插入图片描述

<bean id="person"></bean>

<!--如果构造函数中的对象是引用类型, 则需要用到ref 属性指向-->
<bean id="user" class="User">
	<constructor-arg index="0" name="id" type="java.lang.String" value="01"></constructor-arg>
	<constructor-arg index="1" name="username" type="java.lang.String" ref="person"></constructor-arg>
</bean>

静态工厂方法创建对象

public class Factory {
    public static User getBean() {
        return new User("1", "zhoukang");
    }
}
<bean id="user" class="Factory" factory-method="getBean"></bean>

在这里插入图片描述
非静态工厂方法创建对象

public class Factory {
    public User getBean() {
        return new User("1", "zhoukang");
    }
}
<!--先创建工厂对象-->
<bean id="factory" class="Factory">
<!--指定工厂对象和工厂方法-->
<bean id="user" class="User" factory-bean="factory" factory-method="getBean"></bean>

3. 使用注解的方式来配置 bean 与 IOC 容器

  1. 注解使用xml 配置的方式
<!--在Spring.xml 中引入context 名称空间-->
<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.2.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-4.2.xsd">
       
<!--开启注解扫描器, 会去扫描aa包下的注解-->
<context:component-scan base-package="aa"></context:component-scan>

实体类测试,分别在持久层、业务逻辑层、控制层新建了三个类,互相引用,最后看IOC 容器中是否含有该类

// 将对象添加到IOC容器中时, 首字母会小写
@Repository
public class UserDao {
    public void save() {
        System.out.println("UserDao : save");
    }
}

@Service
public class UserService {
    // 如果Resource 不指定值的话, 就会根据类型(UserDao)去寻找, 一个IOC 容器每个类型都是唯一的. 如果指定了值的话, 就会去寻找id 为userDao 的对象
    @Resource(name = "userDao")
    private UserDao userDao;
    public void save() {
        userDao.save();
    }
}

@Controller
public class UserAction {
    @Resource(name = "userService")
    private UserService userService;
    public String execute() {
        userService.save();
        return "";
    }
}

在这里插入图片描述

  1. 注解使用启动扫描器的方式
// 新增启动扫描类, 自动扫描指定包下的注解

// 表明改类是配置类
@Configuration
// 启动扫描器, 扫描aa包下的, 可同时指定多个包或指定类型
@ComponentScan("aa")
public class AppConfig {
}
// 这时候IOC 容器不需要从XML 中读取配置了, 直接从配置类读取配置即可, 使用AnnotationConfigApplicationContext
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(aa.AppConfig.class);

在这里插入图片描述
创建对象以及处理对象之间的依赖关系, 相关的注解有:

  • @ComponentScan 扫描器, 可指定扫描包、类型
  • @Configuration 表明该类为配置类
  • @Component 指定把一个对象加入IOC 容器, @Name 也考研实现相同的效果(不常用)
  • @Repository 作用同 @Component, 在持久层使用
  • @Service 作用同 @Component, 在业务逻辑层使用
  • @Controller 作用同 @Component, 在控制层使用
  • @Resouce 依赖关系, 如果@Resouce 不指定值, 则会根据类型来查找对象, 如果指定了就会根据名字来查找

持久层、业务层、控制层

  1. 持久层也叫作DAO 层, 主要负责诶数据库做CRUD 操作, 并把这些数据库操作提供给业务层做处理.
  2. 业务层也叫作Service 层, 主要工作是负责组装持久层的数据操作, 把需要的数据封装在实体类中, 并提供最终控制层想要的数据.
  3. 控制层也叫作Controller 层, 主要工作是负责根据传递cookie 参数, session 参数或者前端传过来的参数, 并把这些参数传递给业务层封装好的数据操作, 并把持久层传递过来的数据进行序列化后传递给前端页面. Controller和Service的区别是:Controller负责具体的业务模块流程的控制;Service层负责业务模块的逻辑应用设计
  4. 实体层
  5. 视图层

二、Bean对象的创建细节

对象写死的问题已经解决,IOC 容器就是控制反转创建对象的

1. scope 属性

指定scope 属性,IOC 容器就知道创建对象的时候该对象是单例还是多例的了,不指定的话默认单例。

<!--单例模式-->
<bean id="userDao" class="aa.UserDao" scope="singleton"></bean>

在这里插入图片描述

<!--多例模式-->
<bean id="userDao" class="aa.UserDao" scope="prototype"></bean>

在这里插入图片描述

2. lazy-init 懒加载,init-method 初始化方法

lazy-init属性只对singleton 单例的对象有效,lazy-init 默认为false,前面说了单例模式下的bean 会在IOC 容器创建好之前完成创建,有时候我们想要使用这个bean 的时候他才去创建,将lazy-init 设置为true 即可。

<!--懒加载模式-->
<bean id="userDao" class="aa.UserDao" scope="singleton" lazy-init="true"></bean>

如果想要对象在创建之后执行某个方法,配置init-method即可,IOC 容器销毁后会执行的方法用destroy-method

<!--初始化和销毁方法-->
<bean id="userDao" class="aa.UserDao" scope="singleton" lazy-init="true" init-method="initMethod" destroy-method="desMethod"></bean>

在这里插入图片描述

三、Spring 依赖注入

对象之间的依赖关系,说白了就是给对象上的属性赋值。因为对象上有其他对象的变量,就形成了依赖。Spring中给属性赋值的方法有:

  1. 通过构造函数
  2. 通过set方法给属性注入值
  3. p名称空间
  4. 自动装配
  5. 注解

1. 准备环境

准备三个类,UserActionUserServiceUserDao,三个类中互相依赖。

public class Dao {
    public void save() {
        System.out.println("UserDao : save");
    }
}

public class Service {
    public void save() {
        userDao.save();
    }
}

public class Action {
    public String execute() {
        userService.save();
        return "";
    }
}

2. 通过构造函数

前面也介绍过通过构造函数传值,这里不再赘述。

<!--通过constructor这个节点来指定构造函数的参数类型、名称、第几个-->
<bean id="user" class="User">
	<!--如果构造函数中的对象是引用类型, 则需要用到ref 属性指向-->
	<constructor-arg index="0" name="id" type="java.lang.String" value="01"></constructor-arg>
	<constructor-arg index="1" name="username" type="java.lang.String" ref="person"></constructor-arg>
</bean>

3. 通过set方法给属性注入值(目前项目中使用的就是这种方式)

测试service 层和dao 层的依赖关系就好了,在service 层通过set 方法来把userDao 注入到UserService 中。

<!--创建dao对象-->
<bean id="dao" class="bb.Dao"></bean>

<!--创建service对象, ref中引入dao对象-->
<bean id="service" class="bb.Service">
    <property name="dao" ref="dao"></property>
</bean>
// 在 Service 类中新建set方法, 将xml中配置的对象给注入进来, 这样在Service中就能使用dao的实例了
public class Service {
	public void setDao(Dao dao) {
	    this.dao = dao;
	    System.out.println(dao);
	}
|

在这里插入图片描述
内部bean的方式:在实际场景中看你们会看到引用类型并不是使用ref 的形式,而是内部bean 的方式,二者的效果是一致的。

<!--内部bean, 缺点在于bean不能复用-->
<bean id="service" class="bb.Service">
    <property name="dao">
		<bean id="dao" class="bb.Dao" />
	</property>
</bean>

4. p名称空间注入属性值

P名称空间就是set方法的一种优化,减少了配置的工作量

<!--命名空间需要加上 xmlns:P="http://www.springframework.org/schema/p", 效果等同于ref 引用指向-->
<bean id="service" class="bb.Service" P:dao-ref="dao"></bean>

5. 自动装配 AutoWire

Spring 中提供了自动装配的功能,能够非常简化我们的配置。自动装配默认是不打开的,自动装配根据常用的可分为

  • 根据名字来自动装配
<!--创建dao对象-->
<bean id="dao" name="dao" class="bb.Dao"></bean>

<!--根据名字来自动装配, 当创建service 这个bean 时, 会去容器中寻找是否有叫dao 的对象(因为Service 中有set方法), 如果有则装配进去-->
<bean id="service" class="bb.Service" autowire="byName"></bean>
  • 根据类型来自动装配
<!--创建dao对象-->
<bean id="dao" name="dao" class="bb.Dao"></bean>

<!--根据类型来自动装配, 当创建service 这个bean 时, 会去容器中寻找是否有类型为dao 的对象(因为Service 中有set方法), 如果有则装配进去-->
<bean id="service" class="bb.Service" autowire="byName"></bean>

无论是采用那种自动装配方式,当找到对应的对象时就会自动装配进我们的bean 中,调set 方法,当找不到对应的bean 是就不会注入。
在这里插入图片描述
当多个对象需要自动装配时,可以在xml 配置信息中指定默认的自动装配的方法
在这里插入图片描述

6. 使用注解来实现自动装配

@Autowired 注解可以实现自动装配的功能

  • 可以在构造器上修饰
  • 可以在setter 方法上修饰
  • 来自java 的@inject 的和 @AutoWired有相同的功能
@Service
public class UserService {

    private UserDao userDao;

	// 不使用 @Autowired 注解时
	// @Autowired
    public void setUserDao (UserDao userDao) {
        this.userDao = userDao;
    }

    public void save() {
        userDao.save();
    }
}

在这里插入图片描述
userDao 没有注入进来,将// @Autowired注释取消,实现自动装配
在这里插入图片描述


希望该文章对大家有所帮助!

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-04-18 17:27:33  更:2022-04-18 17:30:47 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 4:18:51-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码