欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring框架之IOC底层原理

程序员文章站 2022-05-24 09:48:29
...

一、Spring中的IOC

  1. IOC:Inversion Of Control 控制反转,该技术是Spring框架的核心技术。作用是将对象的控制权由我们自己转交给Spring框架。
  2. Spring中管理的每个对象称为一个bean,实现IOC的具体操作是在核心配置文件ApplicationContext.xml中配置bean标签,然后使用BeanFactory工厂类来获取对象。

二、具体实现IOC操作

2.1 准备工作
  参考下面该篇博客:
   Spring框架初识及项目搭建
2.2 在项目的src目录下创建一个名字为domain的包,在包中创建一个普通类Student.java
Student.java

public class Student {

    private Integer sid;
    private String sname;
    private String ssex;

    public Student() {}
    public Student(Integer sid, String sname, String ssex) {
        this.sid = sid;
        this.sname = sname;
        this.ssex = ssex;
    }

    public Integer getSid() {
        return sid;
    }
    public void setSid(Integer sid) {
        this.sid = sid;
    }
    public String getSname() {
        return sname;
    }
    public void setSname(String sname) {
        this.sname = sname;
    }
    public String getSsex() {
        return ssex;
    }
    public void setSsex(String ssex) {
        this.ssex = ssex;
    }
}

2.3 在ApplicationContext.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.xsd">

    <bean id="student" class="domain.Student"></bean>

</beans>

分析:只需要在上面的配置文件中配置一个bean标签即可。里面的id属性是给该bean起一个唯一标识,class属性是该类的类全名。

2.4 在src下创建一个名为test的包,包里创建一个名为TestMain.java的测试类。
TestMain.java
原生创建对象方式:

public class TestMain {
    public static void main(String[] args) {
        //原生创建对象方式:没有使用Spring的IOC
        Student student = new Student();
        System.out.println(student);
    }
}

使用Spring IOC技术:

public class TestMain {
    public static void main(String[] args) {
        //使用Spring IOC技术
        BeanFactory factory = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        Student student = (Student) factory.getBean("student");
        System.out.println(student);
    }
}

分析:上面两种方式,第一种是原生的,通过我们自己new出来的;而第二种是先创建一个BeanFactory类工厂的对象,通过调用getBean方法获取到该Student对象。

三、对Spring IOC的深入理解

3.1 之所以我们可以通过BeanFactory类工厂的方式来获取对象,是有原因的:
 * 我们在ApplicationContext.xml中配置了我们想要创建的类对象(bean)信息
 * 在创建BeanFactory工厂类对象时,读取了ApplicationContext.xml文件,因此在创建工厂的时候,工厂类对象就已经知道需要帮我们创建哪些对象
 * 通过getBean方法,在方法的参数中传递一个字符串,该字符串就是我们在ApplicationContext.xml文件中给bean标签的id名称
 * 通过id属性,工厂类对象就找到了配置文件中的该bean标签,就可以找到bean标签中的类全名,有了类全名,底层通过反射技术帮我们创建了该bean对象
 * 最终返回给我们使用,只不过返回的对象是Object类型的,我们需要转型。
总结: 以上的分析步骤就是Spring IOC给我们创建对象的过程,我们需要了解底层原理,才能更好地理解和使用Spring框架。
3.2 通过Spring IOC帮我们创建的对象是单例的吗?
是的,Spring IOC帮我们创建的对象默认就是单例模式,若不想让该对象是单例的,也可以修改。在bean标签中有一个属性为scope,该属性默认是singleton(单例),修改为prototype(原型),意思是每次创建都会是一个新的对象。

//scope属性默认是singleton
<bean id="student" class="domain.Student" scope="prototype"></bean>

3.3 创建的单例对象,是延迟加载的还是立即加载的?
前提说明: 在单例模式中,有饿汉式(立即加载):在项目启动,类加载的时候就创建了该对象;懒汉式(延迟加载):在项目启动,类加载的时候没有创建对象,而是我们什么时候需要了,通过BeanFactory工厂调用getBean方法时创建对象。
验证: 我们可以在Student.java类的无参数构造方法中写一条输出语句,在主函数中不使用BeanFactory工厂类,直接启动主函数,看控制台是否输出了无参数构造方法中的那条语句,如果输出了,就说明是立即加载的,否则就是延迟加载的。
事实: 事实上,通过Spring IOC帮我们创建的对象默认是立即加载的。这种方式在类加载的时候就创建了对象,如果对象很对,会加大内存压力。因此最好是采用延迟加载的方式。
修改: 在bean标签中有一个属性lazy-init,该属性值的默认default和false都是立即加载的意思,我们需要设置该属性值为true,这样我们的对象就是延迟加载的单例模式。

<bean id="student" class="domain.Student" scope="prototype" lazy-init="true"></bean>

扩展:Spring IOC默认创建对象是单例模式,是立即加载;若该为原型模式,原型模式的默认是延迟加载。当然,这些都是可以修改的,最好的方式就是上面的单例延迟加载。