Spring框架之IOC底层原理
一、Spring中的IOC
- IOC:Inversion Of Control 控制反转,该技术是Spring框架的核心技术。作用是将对象的控制权由我们自己转交给Spring框架。
- 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默认创建对象是单例模式,是立即加载;若该为原型模式,原型模式的默认是延迟加载。当然,这些都是可以修改的,最好的方式就是上面的单例延迟加载。
上一篇: JSF 国际化
下一篇: Spring-IOC容器的底层原理