Spring——Spring IOC原理

这篇具有很好参考价值的文章主要介绍了Spring——Spring IOC原理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

摘要

IoC 不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是 松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。其实IoC对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化。应用程序原本是老大,要获取什么资源都是主动出击,但是在IoC/DI思想中,应用程序就变成被动的了,被动的等待IoC容器来创建并注入它所需要的资源了。IoC很好的体现了面向对象设计法则之一。即由IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。

一、IOC的基础概念

  • Spring框架管理这些Bean的创建工作,即由用户管理Bean转变为框架管理Bean,这个就叫控制反转 - Inversion of Control (IoC)
  • Spring 框架托管创建的Bean放在哪里呢? 这便是IoC Container;
  • Spring 框架为了更好让用户配置Bean,必然会引入不同方式来配置Bean? 这便是xml配置,Java配置,注解配置等支持
  • Spring 框架既然接管了Bean的生成,必然需要管理整个Bean的生命周期等;
  • 应用程序代码从Ioc Container中获取依赖的Bean,注入到应用程序中,这个过程叫 依赖注入(Dependency Injection,DI) ; 所以说控制反转是通过依赖注入实现的,其实它们是同一个概念的不同角度描述。通俗来说就是IoC是设计思想,DI是实现方式
  • 在依赖注入时,有哪些方式呢?这就是构造器方式,@Autowired, @Resource, @Qualifier... 同时Bean之间存在依赖(可能存在先后顺序问题,以及循环依赖问题等)。

1.1 Spring Bean

Spring里面的bean就类似是定义的一个组件,而这个组件的作用就是实现某个功能的,这里所定义的bean就相当于给了你一个更为简便的方法来调用这个组件去实现你要完成的功能。

Spring Bean的生命周期 四个阶段

  1. 实例化 Instantiation
  2. 属性赋值 Populate
  3. 初始化 Initialization
  4. 销毁 Destruction

Spring——Spring IOC原理,Spring框架,spring,java,数据库

Spring——Spring IOC原理,Spring框架,spring,java,数据库

1.2 IOC

Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。

  • 谁控制谁,控制什么?:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对 象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。
  • 为何是反转,哪些方面反转了?:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。
  • 用图例说明一下?:传统程序设计下,都是主动去创建相关对象然后再组合起来:

Spring——Spring IOC原理,Spring框架,spring,java,数据库

当有了IoC/DI的容器后,在客户端类中不再主动去创建这些对象了,如图:

Spring——Spring IOC原理,Spring框架,spring,java,数据库

1.3 IoC和DI是什么关系

控制反转是通过依赖注入实现的,其实它们是同一个概念的不同角度描述。通俗来说就是IoC是设计思想,DI是实现方式。DI即依赖注入:组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。

  • 谁依赖于谁?:当然是应用程序依赖于IoC容器;
  • 为什么需要依赖?:应用程序需要IoC容器来提供对象需要的外部资源;
  • 谁注入谁?:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象;
  • 注入了什么?:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。
  • IoC和DI有什么关系呢?:其实它们是同一个概念的不同角度描述,由于控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系),所以2004年大师级人物Martin Fowler又给出了一个新的名字:“依赖注入”,相对IoC 而言,“依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”。通俗来说就是IoC是设计思想,DI是实现方式

二、IOC的配置三种方式

Spring IOC已经给出了三种配置方式,这里再总结下;总体上目前主流方式是注解 + Java 配置

2.1 XML配置

顾名思义,就是将bean的信息配置.xml文件里,通过Spring加载文件为我们创建bean。这种方式出现很多早前的SSM项目中,将第三方类库或者一些配置工具类都以这种方式进行配置,主要原因是由于第三方类不支持Spring注解。

  • 优点: 可以使用于任何场景,结构清晰,通俗易懂

  • 缺点: 配置繁琐,不易维护,枯燥无味,扩展性差

举例

  1. 配置xx.xml文件
  2. 声明命名空间和配置bean
<?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
 http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- services -->
<bean id="userService" class="tech.pdai.springframework.service.UserServiceImpl">
        <property name="userDao" ref="userDao"/>
        <!-- additional collaborators and configuration for this bean go here -->
    </bean>
    <!-- more bean definitions for services go here -->
</beans>

2.2 Java 配置

将类的创建交给我们配置的JavcConfig类来完成,Spring只负责维护和管理,采用纯Java创建方式。其本质上就是把在XML上的配置声明转移到Java配置类中

  • 优点:适用于任何场景,配置方便,因为是纯Java代码,扩展性高,十分灵活

  • 缺点:由于是采用Java类的方式,声明不明显,如果大量配置,可读性比较差

举例

  1. 创建一个配置类, 添加@Configuration注解声明为配置类
  2. 创建方法,方法上加上@bean,该方法用于创建实例并返回,该实例创建后会交给spring管理,方法名建议与实例名相同(首字母小写)。注:实例类不需要加任何注解
/**
 * @author xjl
 */
@Configuration
public class BeansConfig {

    /**
     * @return user dao
     */
    @Bean("userDao")
    public UserDaoImpl userDao() {
        return new UserDaoImpl();
    }

    /**
     * @return user service
     */
    @Bean("userService")
    public UserServiceImpl userService() {
        UserServiceImpl userService = new UserServiceImpl();
        userService.setUserDao(userDao());
        return userService;
    }
}

2.3 注解配置

通过在类上加注解的方式,来声明一个类交给Spring管理,Spring会自动扫描带有@Component,@Controller,@Service,@Repository这四个注解的类,然后帮我们创建并管理,前提是需要先配置Spring的注解扫描器。

  • 优点:开发便捷,通俗易懂,方便维护。

  • 缺点:具有局限性,对于一些第三方资源,无法添加注解。只能采用XML或JavaConfig的方式配置

举例

  1. 对类添加@Component相关的注解,比如@Controller,@Service,@Repository
  2. 设置ComponentScan的basePackage, 比如<context:component-scan base-package='tech.pdai.springframework'>, 或者@ComponentScan("tech.pdai.springframework")注解,或者 new AnnotationConfigApplicationContext("tech.pdai.springframework")指定扫描的basePackage.
/**
 * @author xjl
 */
@Service
public class UserServiceImpl {

    /**
     * user dao impl.
     */
    @Autowired
    private UserDaoImpl userDao;

    /**
     * find user list.
     *
     * @return user list
     */
    public List<User> findUserList() {
        return userDao.findUserList();
    }

}

三、依赖注入的三种方式

常用的注入方式主要有三种:构造方法注入(Construct注入),setter注入,基于注解的注入(接口注入)。

3.1 setter方式

在XML配置方式中,property都是setter方式注入,比如下面的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
 http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- services -->
    <bean id="userService" class="tech.pdai.springframework.service.UserServiceImpl">
        <property name="userDao" ref="userDao"/>
        <!-- additional collaborators and configuration for this bean go here -->
    </bean>
    <!-- more bean definitions for services go here -->
</beans>

本质上包含两步:

  1. 第一步,需要new UserServiceImpl()创建对象, 所以需要默认构造函数
  2. 第二步,调用setUserDao()函数注入userDao的值, 所以需要setUserDao()函数

所以对应的service类是这样的:

public class UserServiceImpl {

    /**
     * user dao impl.
     */
    private UserDaoImpl userDao;

    /**
     * init.
     */
    public UserServiceImpl() {
    }

    /**
     * find user list.
     *
     * @return user list
     */
    public List<User> findUserList() {
        return this.userDao.findUserList();
    }

    /**
     * set dao.
     *
     * @param userDao user dao
     */
    public void setUserDao(UserDaoImpl userDao) {
        this.userDao = userDao;
    }
}

在注解和Java配置方式下

public class UserServiceImpl {

    /**
     * user dao impl.
     */
    private UserDaoImpl userDao;

    /**
     * find user list.
     *
     * @return user list
     */
    public List<User> findUserList() {
        return this.userDao.findUserList();
    }

    /**
     * set dao.
     *
     * @param userDao user dao
     */
    @Autowired
    public void setUserDao(UserDaoImpl userDao) {
        this.userDao = userDao;
    }
}

在Spring3.x刚推出的时候,推荐使用注入的就是这种, 但是这种方式比较麻烦,所以在Spring4.x版本中推荐构造函数注入。

3.2 构造函数

在XML配置方式中<constructor-arg>是通过构造函数参数注入,比如下面的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
 http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- services -->
    <bean id="userService" class="tech.pdai.springframework.service.UserServiceImpl">
        <constructor-arg name="userDao" ref="userDao"/>
        <!-- additional collaborators and configuration for this bean go here -->
    </bean>
    <!-- more bean definitions for services go here -->
</beans>

本质上是new UserServiceImpl(userDao)创建对象, 所以对应的service类是这样的:

public class UserServiceImpl {

    /**
     * user dao impl.
     */
    private final UserDaoImpl userDao;

    /**
     * init.
     * @param userDaoImpl user dao impl
     */
    public UserServiceImpl(UserDaoImpl userDaoImpl) {
        this.userDao = userDaoImpl;
    }

    /**
     * find user list.
     *
     * @return user list
     */
    public List<User> findUserList() {
        return this.userDao.findUserList();
    }

}

在注解和Java配置方式下

@Service
public class UserServiceImpl {

    /**
     * user dao impl.
     */
    private final UserDaoImpl userDao;

    /**
     * init.
     * @param userDaoImpl user dao impl
     */
    @Autowired // 这里@Autowired也可以省略
    public UserServiceImpl(final UserDaoImpl userDaoImpl) {
        this.userDao = userDaoImpl;
    }

    /**
     * find user list.
     *
     * @return user list
     */
    public List<User> findUserList() {
        return this.userDao.findUserList();
    }
}

3.3 注解注入

以@Autowired(自动注入)注解注入为例,修饰符有三个属性:Constructor,byType,byName。默认按照byType注入。

  • constructor:通过构造方法进行自动注入,spring会匹配与构造方法参数类型一致的bean进行注入,如果有一个多参数的构造方法,一个只有一个参数的构造方法,在容器中查找到多个匹配多参数构造方法的bean,那么spring会优先将bean注入到多参数的构造方法中。
  • byName:被注入bean的id名必须与set方法后半截匹配,并且id名称的第一个单词首字母必须小写,这一点与手动set注入有点不同。
  • byType:查找所有的set方法,将符合符合参数类型的bean注入。
@Service
public class UserServiceImpl {

    /**
     * user dao impl.
     */
    @Autowired
    private UserDaoImpl userDao;

    /**
     * find user list.
     *
     * @return user list
     */
    public List<User> findUserList() {
        return userDao.findUserList();
    }

}

博文参考

Spring基础 - Spring核心之控制反转(IOC) | Java 全栈知识体系文章来源地址https://www.toymoban.com/news/detail-704810.html

到了这里,关于Spring——Spring IOC原理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Spring Boot】数据库持久层框架MyBatis — MyBatis简介

    本节首先会介绍什么是ORM、什么是MyBatis、MyBatis的特点以及核心概念,最后介绍MyBatis是如何启动、如何加载配置文件的? ORM(Object Relational Mapping,对象关系映射)是为了解决面向对象与关系数据库存在的互不匹配现象的一种技术。简单地说,ORM通过使用描述对象和数据库之

    2024年02月11日
    浏览(34)
  • spring框架,以及和spring框架相关的Java面试题和spring ioc的注入方式

    目录 一.spring来源,以及介绍 1.spring诞生的背景 2.spring框架 介绍 3.spring框架在使用中的优点以及不足 3.1优点  3.2不足 3.3总结 4.为什么要使用spring  二.将spring框架部署在IDEA中  1.替换pom.xml  2.构建spring所需要的xml文件 三.spring的三种注入方式 0.定义需要的类,方法 1.方法注入

    2024年02月12日
    浏览(37)
  • layui+java spring 实现图片文件新增到数据库

    layui+java spring 实现图片文件新增到数据库 1.首先layui是个不再更新的网址有想了解的可以浏览官网 表格组件 table - Layui 文档 2.官网内有专门的组件 代码直接粘过来即可 !DOCTYPE html html head   meta charset=\\\"utf-8\\\"   meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1\\\"   titleDemo/title  

    2024年02月07日
    浏览(27)
  • Java(一):创建 Spring Boot 项目并实现连接操作MySQL数据库

    MySQL 命令 Maven 相关地址 下载地址: https://maven.apache.org/ maven配置方法地址: https://developer.aliyun.com/mvn/guide 仓库搜索地址: https://mvnrepository.com/ https://repo.maven.apache.org/ maven 本地配置 conf/settings.xml 下载 idea 并配置本地环境 maven Maven 构建 生命周期 Maven 的构建 生命周期 包括 三

    2024年02月07日
    浏览(53)
  • Spring——Spring IOC原理

    IoC 不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查找依赖对象的控制权交给了容器

    2024年02月09日
    浏览(37)
  • 【Spring框架二】——什么是Spring IOC、 什么是Spring 依赖注入

    【Spring框架一】——Spring框架简介 【Spring框架三】——Spirng IOC和DI的实现 本篇博客主要讲解的是Spring 的IOC以及DI(依赖注入)的基本概念和优势利弊,如果想知道如何实现Spring IOC与DI可以访问博主的另外一篇博客。 【Spring框架三】——Spirng IOC和DI的实现 它的核心思想是将对

    2024年02月06日
    浏览(33)
  • 【框架源码】手写Spring框架IOC容器核心流程

    要是想要了解Spring IOC底层,首先我们就得先了解什么是IOC。 IOC就是控制反转,把对象创建和对象之间的调用过程交给Spring进行管理。 使用IOC目的就是之前我们创建对象的方式都是用new的方式创建,这个方式有个缺点,被创建对象的类的位置一旦被改动,new就会报错,类与类

    2024年02月06日
    浏览(45)
  • 【Spring】Spring的数据库开发

    1.1 Spring JdbcTemplate的解析     针对数据库的操作,Spring框架提供了 JdbcTemplate 类,该类是Spring框架数据抽象层的基础,其他更高层次的抽象类是构建于JdbcTemplate类之上的。可以说,JdbcTemplate类是Spring JDBC的核心类。JdbcTemplate类的继承关系十

    2023年04月23日
    浏览(31)
  • Spring框架中IOC和DI详解

    来源黑马Spring课程,觉得挺好的 1、为什么要学习spring? 如果让本人用一句话去回答这个问题,那么我只能说:在J2EE的学习之路上,spring给我带来了开发的春天,让我们从JSP、sevlet的高耦合的开发中彻底的解救出来。 spring是目前最主流的框架 spring是学习后面课程(比如:

    2023年04月15日
    浏览(43)
  • Spring IOC底层原理实现过程

    Spring IOC(Inversion of Control,控制反转)是 Spring 框架的核心,它的实现原理是基于反射和配置文件实现的。 在 Spring IOC 中,控制权被反转了。传统的应用程序开发中,对象的创建、管理、销毁等全部由应用程序自己来控制,这个过程称为主动管理(Active Management)。而在 Spr

    2024年02月03日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包