【Spring】IOC,你真的懂了吗?

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

作者:狮子也疯狂
专栏:《spring开发》
坚持做好每一步,幸运之神自然会驾凌在你的身上
【Spring】IOC,你真的懂了吗?,# spring开发,spring,java,前端,spring boot,intellij-idea

一. 🦁 前言

Spring框架是狮子入坑Java的第一个开源框架。当我们接触到它时,总会发现老师或者书本介绍这两个词汇——IOC和AOP,它们分别是控制反转和面向切面,是Spring的思想内核,提供了控制层SpringMVC、数据层SpringData、服务层事务管理等众多技术,并可以整合众多第三方框架。现在我们通过自己手写一个简单的模板来深入地认识一下IOC

二. 🦁 控制反转(IOC)

【Spring】IOC,你真的懂了吗?,# spring开发,spring,java,前端,spring boot,intellij-idea

Ⅰ. 🐇主要思想

IOC(Inversion of Control) :程序将创建对象的权利交给框架,框架会帮助我们创建对象,分配对象的使用,控制权由程序代码转移到了框架中,控制权发生了反转,这就是Spring的IOC思想。

Ⅱ. 🐇原生技术创建实例弊端

我们之前在开发过程中,对象实例的创建是由调用者直接管理的,在每个层,需要用到某个对象时,都需要重新实现。我们通过一个简单的例子,来搞清楚这个方法的弊端:

public interface StudentDao {    
	// 根据id查询学生
    Student findById(int id);
 }
public class StudentDaoImpl implements StudentDao{
    @Override
   public Student findById(int id) {
          // 模拟从数据库查找出学生
         return new Student(1,"JackieYe","茂名");
   }
}
public class StudentService {
    public Student findStudentById(int id){
           // 此处就是调用者在创建对象
        StudentDao studentDao = new StudentDaoImpl();
        return studentDao.findById(1);
   }
}

这样的写法,缺点有二:

  • 浪费资源:StudentService调用方法时即会创建一个对象,如果不断调用 方法则会创建大量StudentDao对象。
  • 代码耦合度高:假设随着开发,我们创建了StudentDao另一个更加完善的实现类StudentDaoImpl2,如果在StudentService中想使StudentDaoImpl2,则必须修改源码。

Ⅲ. 🐇自定义对象容器

现在我们来通过一段手写代码模拟一下spring的IOC思想。过程如下:

  1. 创建一个集合容器。
  2. 创建对象,然后放到容器中。
  3. 从容器中获取对象。

3.1 准备数据

在此之前,我们先准备一点数据,我们在上面的例子的基础上,再添加一个StudentDao实例:

public interface StudentDao {    
	// 根据id查询学生
    Student findById(int id);
 }
public class StudentDaoImpl implements StudentDao{
    @Override
   public Student findById(int id) {
          // 模拟从数据库查找出学生
         return new Student(1,"JackieYe","茂名");
   }
}
//重新实例化一个,数据一样,再在控制台输出一句话。
public class StudentDaoImpl2 implements StudentDao{
    @Override
    public Student findById(int id) {
        // 模拟根据id查询学生
        System.out.println("新方法!!!");
        return new Student(1,"JackieYe","茂名");
   }
}

3.2 创建配置文件

创建配置文件bean.properties,该文件中定义管理的对象。

前面我们添加了一个StudentDaoImpl2,如果需要调用它,则只需要更改该配置文件的名字,并不需要更改源代码。

studentDao=com.jackie.dao.StudentDaoImpl

3.3 创建容器管理类

创建容器管理类,该类在类加载时读取配置文件,将配置文件中配置的对象全部创建并放入容器中。代码如下:

public class Container {
    static Map<String,Object> map = new HashMap();
    static {
        // 读取配置文件
      InputStream is = Container
                       .class.getClassLoader()
      			       .getResourceAsStream("bean.properties");
      Properties properties = new Properties();
        try {
           properties.load(is);
      }catch(IOException e) {
           e.printStackTrace();
            }
                // 遍历配置文件的所有配置
      Enumeration<Object> keys = properties.keys();
      while (keys.hasMoreElements()){
            String key = keys.nextElement().toString();
            String value = properties.getProperty(key);
            try {
                // 创建对象
                Object o = Class.forName(value).newInstance();
                // 将对象放入集合中
                map.put(key,o);
           } catch (Exception e) {
                e.printStackTrace();
           }
       }
   }
		    // 从容器中获取对象
	public static Object getBean(String key){
        return map.get(key);
   }
}

我们创建了一个名为Container的对象,并且通过反射的方式将其读入了输入流,然后遍历该配置文件的配置,将其放入一个枚举类keys里面,然后遍历该keys,在循环里创建对象实例,放到map集合里。

3.4 创建StudentService对象

创建Dao对象的调用者StudentService。

public class StudentService {
    public Student findStudentById(int id){
        // 从容器中获取对象
        StudentDao studentDao = (StudentDao)Container.getBean("studentDao");
		System.out.println(studentDao.hashCode());
        return studentDao.findById(id);
   }
}

3.5 测试StudentService

测试代码如下:

public class Test {
    public static void main(String[] args){
      StudentService studentService = new StudentService();
      System.out.println(studentService.findStudentById(1));
      System.out.println(studentService.findStudentById(1));
   }
}

我们来总结一下控制反转是如何来解决上面我们用原生技术探索出来的两个弊端的:

  • 我们会发现,无论调用多少次,这个对象的hashcode都是一样的,节约了资源。(如果是原生方法创建,hashcode肯定会变化)
  • 如果我们需要用到StudentDaoImpl2对象,只需要修改bean.properties的内容为
    studentDao=com.jackie.dao.StudentDaoImpl2即可,无需修改源代码。

Ⅳ. 🐇Spring实现IOC

【Spring】IOC,你真的懂了吗?,# spring开发,spring,java,前端,spring boot,intellij-idea

4.1 创建Maven工程

添加如下依赖:

<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.13</version>
  </dependency>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
  </dependency>
</dependencies>

4.2 创建dao

这里我们还是使用第一个例子来说明,方便小伙伴对比。

4.3 编写xml配置文件

编写xml配置文件,配置文件中配置需要Spring帮我们创建的对象。

<?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">
  <bean id="studentDao" class="com.jackie.dao.StudentDaoImpl"></bean>  
</beans>

4.4 测试

测试从Spring容器中获取对象

public class TestContainer {
  @Test
  public void t1(){
    // 创建Spring容器
    ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
    // 从容器获取对象
    StudentDao studentDao1 = (StudentDao) ac.getBean("studentDao");
    StudentDao studentDao2 = (StudentDao) ac.getBean("studentDao");
    System.out.println(studentDao1.hashCode());
    System.out.println(studentDao2.hashCode());
    System.out.println(studentDao1.findById(1));
   }
}

我们通过控制台第一行和第二行的结果会发现,俩个hashcode值是一样的。说明通过spring容器获取的对象也是和前面自定义容器一样,不会再次实例化。

Ⅵ. 🐇常见的spring容器类型

【Spring】IOC,你真的懂了吗?,# spring开发,spring,java,前端,spring boot,intellij-idea
Spring的接口以及实现类型如上,红圈标注的类是我们常用的五个容器类型。我们来探究一下这个五个类的作用。

6.1 容器接口

BeanFactory:BeanFactory是Spring容器中的顶层接口,它可以对Bean对象进行管理。
ApplicationContext:ApplicationContext是BeanFactory的子接口。它除了继承 BeanFactory的所有功能外,还添加了对国际化、资源访问、事件传播等方面的良好支持。
ApplicationContext有以下三个常用实现类:

  • ClassPathXmlApplicationContext:该类可以从项目中读取配置文件
  • FileSystemXmlApplicationContext:该类从磁盘中读取配置文件
  • AnnotationConfigApplicationContext:使用该类不读取配置文件,而是会读取注解

前面我们已经使用过ClassPathXmlApplicationContext类,他就是专门读取项目的xml文件,而FileSystemXmlApplicationContext类则是需要读取硬盘里面的xml文件,所以它需要输入文件的绝对路径。而AnnotationConfigApplicationContext类的使用则简单多,它里面不用写,直接读取注解的配置。这里是介绍IOC的原理,spring容器的创建则不多作阐述。

Ⅶ. 🐇IOC生命周期方法

【Spring】IOC,你真的懂了吗?,# spring开发,spring,java,前端,spring boot,intellij-idea
Bean对象的生命周期包含创建——使用——销毁,Spring可以配置Bean对象在创建和销毁时自动执行的方法,我们用来判断对象的创建以及销毁时间。
配置生命周期以及销毁周期:

<!-- init-method:创建对象时执行的方法 
destroy-method:销毁对象时执行的方法 -->
<bean id="studentDao"
class="com.jackie.dao.StudentDaoImpl2"
scope="singleton"
      init-method="init" 
      destroy-method="destory">
</bean>

Ⅷ. 🐇依赖注入

【Spring】IOC,你真的懂了吗?,# spring开发,spring,java,前端,spring boot,intellij-idea

8.1 原理

依赖注入(Dependency Injection,简称DI),它是Spring控制反转思想的具体实现。
控制反转将对象的创建交给了Spring,但是对象中可能会依赖其他对象。比如service类中要有dao类的属性,我们称service依赖于dao。之前需要手动注入属性值,代码如下(还是以第一个例子为基础):

public class StudentService {
  // service依赖dao,手动注入属性值,即手动维护依赖关系
  private StudentDao studentDao = new StudentDaoImpl();

  public Student findStudentById(int id){
    return studentDao.findById(id);
   }
}

此时,当StudentService的想要使用StudentDao的另一个实现类如StudentDaoImpl2时,则需要修改Java源码,造成代码的可维护性降低。
而使用Spring框架后,Spring管理Service对象与Dao对象,此时它能够为Service对象注入依赖的Dao属性值。这就是Spring的依赖注入。简单来说,控制反转是创建对象,依赖注入是为对象的属性赋
值。

8.2 注入方式

spring一共有三种方式注入,分别是Setter注入,构造方法注入和自动注入。

8.2.1 Setter注入

1.被注入类编写属性的setter方法

public class StudentService {
    private StudentDao studentDao;
    public void setStudentDao(StudentDao studentDao) {
        this.studentDao = studentDao;
   }
}

2.配置文件中,给需要注入属性值的 bean 中设置 property

<bean id="studentDao"
class="com.jackie.dao.StudentDaoImpl">
</bean>
<bean id="studentService"
class="com.jackie.service.StudentService">
    <!--依赖注入-->
    <!--name:对象的属性名 ref:容器中对象的id值-->
    <property name="studentDao" ref="studentDao"></property>
</bean>
  1. 测试是否注入成功
@Test
public void t2(){
    ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
    StudentService studentService = (StudentService)ac.getBean("studentService");
    System.out.println(studentService.findStudentById(1));
}
8.2.2 构造方法注入
  1. 被注入类编写有参的构造方法
public class StudentService {
    private StudentDao studentDao;
    public StudentService(StudentDao studentDao) {
        this.studentDao = studentDao;
   }
}
  1. 给需要注入属性值的 bean中设置 constructor-arg
<bean id="studentDao"
class="com.jackie.dao.StudentDaoImpl">
</bean>
<bean id="studentService"
class="com.jackie.service.StudentService">
    <!-- 依赖注入 -->
    <!-- name:对象的属性名 ref:配置文件中注入对象的id值 -->
    <constructor-arg name="studentDao" ref="studentDao"></constructor-arg>
</bean>
  1. 测试是否注入成功

同上一个测试方法。

8.2.3 自动注入

自动注入不需要在 bean标签中添加其他标签注入属性值,而是自动从容器中找到相应的bean对象设置为属性值。

tips:
自动注入有两种配置方式:

  • 全局配置:在 中设置 default-autowire 属性可以定义所有bean对象的自动注入策略。
  • 局部配置:在 中设置 autowire 属性可以定义当前bean对象的自动注入策略

autowire的取值如下:

  • no:不会进行自动注入。 default:全局配置default相当于no,局部配置default表示使用全局配置
  • byName:在Spring容器中查找id与属性名相同的bean,并进行注入。需要提供set方法。
  • byType:在Spring容器中查找类型与属性类型相同的bean,并进行注入。需要提供set方法。
  • constructor:在Spring容器中查找id与属性名相同的bean,并进行注入。需要提供构造方法
  1. 配置自动注入
<!-- 根据beanId等于属性名自动注入 -->
<bean id="studentDao" class="com.jackie.dao.StudentDaoImpl"></bean>
<bean id="studentService" class="com.jackie.service.StudentService" autowire="byName"></bean>
<!-- 根据bean类型等于属性类型自动注入 -->
<bean id="studentDao" class="com.jackie.dao.StudentDaoImpl"></bean>
<bean id="studentService" class="com.jackie.service.StudentService" autowire="byType"></bean>

<!-- 利用构造方法自动注入 -->
<bean id="studentDao" class="com.jackie.dao.StudentDaoImpl"></bean>
<bean id="studentService" class="com.jackie.service.StudentService" autowire="constructor"></bean>
<!-- 配置全局自动注入 -->
<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"
    default-autowire="constructor">

三. 🦁总结

本文通过对比原生Java技术加载对象与手写模拟IOC技术来加载对象,突出了spring的IOC功能的强大;另外,还介绍了IOC的生命周期以及IOC的依赖注入方法,以及依赖注入的原理。总的来说,spring很强大,但是配置繁琐,我们已经使用springboot来取代了,但是spring是基础框架,该理解还是得去理解,希望这篇文章可以帮到你。😄文章来源地址https://www.toymoban.com/news/detail-828236.html

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

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

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

相关文章

  • spring 详解五 IOC(注解开发)

    注解开发已经成为开发的主流选择,例如springboot都是基于注解开发使用的spring,所以学习注解开发是很有必要的,基本Bean注解, 主要是使用注解的方式替代原有xml的bean 标签及其标签属性的配置 XML 配置 注解 描述 bean id=“” class=“” @Component 被该注解标识的类,会在指定扫

    2024年02月13日
    浏览(38)
  • 【Spring篇】IOC/DI注解开发

    🍓系列专栏:Spring系列专栏 🍉个人主页:个人主页 目录 一、IOC/DI注解开发 1.注解开发定义bean  2.纯注解开发模式 1.思路分析 2.实现步骤 3.注解开发bean作用范围与生命周期管理 1.环境准备 2.Bean的作用范围 3.Bean的生命周期 4.注解开发依赖注入 1.环境准备 2.注解实现按照类型注入

    2024年02月03日
    浏览(76)
  • 【Spring教程九】Spring框架实战:全面深入详解IOC/DI注解开发

    欢迎大家回到《 Java教程之Spring30天快速入门》,本教程所有示例均基于Maven实现,如果您对Maven还很陌生,请移步本人的博文《 如何在windows11下安装Maven并配置以及 IDEA配置Maven环境》,本文的上一篇为《 IOC/DI配置管理第三方bean 加载properties文件》。 Spring的IOC/DI对应的配置开

    2024年02月03日
    浏览(49)
  • 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日
    浏览(51)
  • 【Java EE】Spring核心思想(一)——IOC

    通过前⾯的学习, 我们知道了Spring是⼀个开源框架, 他让我们的开发更加简单. 他⽀持⼴泛的应⽤场 景, 有着活跃⽽庞⼤的社区, 这也是Spring能够⻓久不衰的原因. 但是这个概念相对来说, 还是⽐较抽象. 我们⽤⼀句更具体的话来概括Spring, 那就是: Spring 是包含了众多⼯具⽅法的

    2024年04月23日
    浏览(54)
  • 【Java面试】Spring中的IOC和AOP

    IOC:控制反转也叫依赖注入。利用了工厂模式 将对象交给容器管理,你只需要在spring配置文件总配置相应的bean,以及设置相关的属性,让spring容器来生成类的实例对象以及管理对象。在spring容器启动的时候,spring会把你在配置文件中配置的bean都初始化好,然后在你需要调用的

    2024年02月10日
    浏览(50)
  • 11Spring IoC注解式开发(下)(负责注入的注解/全注解开发)

    负责注入的注解,常见的包括四个: @Value @Autowired @Qualifier @Resource 当属性的类型是简单类型时,可以使用@Value注解进行注入。 @Value注解可以出现在属性上、setter方法上、以及构造方法的形参上, 方便起见,一般直接作用在属性上. 配置文件开启包扫描: 测试程序: 三种方法都可

    2024年01月16日
    浏览(48)
  • 【Spring教程11】Spring框架实战:IOC/DI注解开发管理第三方bean的全面深入详解

    欢迎大家回到《 Java教程之Spring30天快速入门》,本教程所有示例均基于Maven实现,如果您对Maven还很陌生,请移步本人的博文《 如何在windows11下安装Maven并配置以及 IDEA配置Maven环境》,本文的上一篇为《 纯注解开发模式下的依赖注入和读取properties配置文件》 前面定义bean的时

    2024年02月04日
    浏览(61)
  • 【Java学习】 Spring的基础理解 IOC、AOP以及事务

        官网: https://spring.io/projects/spring-framework#overview     官方下载工具: https://repo.spring.io/release/org/springframework/spring/     github下载: https://github.com/spring-projects/spring-framework     maven依赖: 1.spring全家桶的结构构图:              最下边的是测试单元   其中spring封装

    2024年02月09日
    浏览(43)
  • java八股文面试[Spring]——如何实现一个IOC容器

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

    2024年02月10日
    浏览(48)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包