什么是IOC
IOC,Inversion of Control,控制反转。是一种设计思想。
传统的创建对象的方法是直接通过new关键字,而Spring则是通过IOC容器来创建对象的,也就是将创建对象的控制权交给了IOC容器。
一句话:IOC让程序员不住关注怎么去创建对象,而是关注与对象创建之后的操作,把对象的创建、初始化、销毁等工作交给了Spring容器
Spring 容器创建对象的三种方式
第一步:创建项目,导入maven依赖,如下图:
第二步:创建测试对象 HelloIoc
public class HelloIoc{
public void sayHello(){
System.out.println("Hello IOC");
}
}
传统方法创建对象
public class App {
public static void main( String[] args ){
HelloIoc helloIoc = new HelloIoc();
helloIoc.sayHello();
}
}
通过Spring容器来创建:
第一种方法:利用默认构造方法
在src目录下新建applicationContext.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">
<!--
创建对象的第一种方式:利用无参构造器
id:唯一标识符
class:类的全类名
-->
<bean id="helloIoc" class="com.rzjt.ioc.HelloIoc" ></bean>
<!-- 别名属性 name:和bean的 id 属性对应 -->
<alias name="helloIoc" alias="helloIoc2"/>
</beans>
测试
public class App {
public static void main( String[] args ){
//启动 spring 容器
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//从 spring 容器获取对象
HelloIoc helloIoc = (HelloIoc) context.getBean("helloIoc");
helloIoc.sayHello();
//利用配置文件 alias 别名属性创建对象
HelloIoc helloIoc2 = (HelloIoc) context.getBean("helloIoc2");
helloIoc2.sayHello();
context.close();
}
}
在类HelloIoc中手动添加无参的构造方法,然后执行上面的测试代码,会发现构造方法会在sayHello方法前调用
第二种方法:利用静态工厂方法
创建静态工厂类:
public class HelloStaticFactory{
public HelloStaticFactory(){
System.out.println("Hellostaticfactory");
}
//静态工厂方法
public static HelloIoc getInstance(){
return new HelloIoc();
}
}
在applicationContext.xml中配置
<!--
创建对象的第二种方式:利用静态工厂方法
factory-method:静态工厂类的获取对象的静态方法
class:静态工厂类的全类名
-->
<bean id="helloStaticFactory" factory-method="getInstances" class="com.rzjt.ioc.HelloStaticFactory"></bean>
测试
public class App {
public static void main( String[] args ){
//启动 spring 容器
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloIoc staticFactory = (HelloIoc) context.getBean("helloStaticFactory");
staticFactory.sayHello();
context.close();
}
}
spring只负责调用静态工厂方法,这个静态方法内部实现由程序员完成
第三种方法:利用实例工厂方法
创建实例工厂类HelloInstanceFactory
public class HelloInstanceFactory{
public HelloInstanceFactory(){
System.out.println("实例工厂构造方法");
}
//实例工厂方法创建对象
public HelloIoc getInstance(){
return new HelloIoc();
}
}
在applicationContext.xml中进行配置:
<!--
创建对象的第三种方式:利用实例工厂方法
factory-bean:指定当前Spring中包含工厂方法的beanID
factory-method:工厂方法名称
-->
<bean id="instanceFactory" class="com.rzjt.ioc.HelloInstanceFactory"></bean>
<bean id="instance" factory-bean="instanceFactory" factory-method="getInstance"></bean>
测试
public class App {
public static void main( String[] args ){
//启动 spring 容器
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloIoc instanceFactory = (HelloIoc) context.getBean("instance");
instanceFactory.sayHello();
context.close();
}
}
Spring 容器创建对象的时机
第一种:默认情况下,启动spring容器就创建对象(遇到bean便创建对象)
在HelloIoc中添加默认构造方法:
public class HelloIoc{
//默认无参构造方法
public HelloIoc(){
System.out.println("HelloIoc default constructor");
}
public void sayHello(){
System.out.println("Hello IOC");
}
}
在applicationContext.xml 中添加 bean,现在里面有三个bean了
启动容器测试
public class App {
public static void main( String[] args ){
//启动 spring 容器
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//从 spring 容器获取对象
HelloIoc helloIoc = (HelloIoc) context.getBean("helloIoc");
helloIoc.sayHello();
//利用配置文件 alias 别名属性创建对象
HelloIoc helloIoc2 = (HelloIoc) context.getBean("helloIoc2");
helloIoc2.sayHello();
HelloIoc staticFactory = (HelloIoc) context.getBean("helloStaticFactory");
staticFactory.sayHello();
HelloIoc instanceFactory = (HelloIoc) context.getBean("instance");
instanceFactory.sayHello();
context.close();
}
}
看到结果
HelloIoc default constructor
HelloIoc default constructor
实例工厂构造方法
HelloIoc default constructor
Hello IOC
Hello IOC
Hello IOC
Hello IOC
第二种:在spring的配置文件bean中有一个属性lazy-init="default/true/false"
- 如果lazy-init为default 或 false 在启动spring容器时创建对象(默认情况)
- 如果lazy-init为true时 在context.getBean时才创建对象
修改applicationContext.xml
<!--
创建对象的第一种方式:利用无参构造器
id:唯一标识符
class:类的全类名
-->
<bean id="helloIoc" class="com.rzjt.ioc.HelloIoc" lazy-init = "true" ></bean>
执行结果变为了
HelloIoc default constructor
实例工厂构造方法
HelloIoc default constructor
HelloIoc default constructor
Hello IOC
Hello IOC
Hello IOC
Hello IOC
在第一种情况下可以在启动spring容器时,检查spring容器配置文件的正确性,但是这样的缺点是把一些bean过早的放在了内存中,如果数据量大,堆内存是消耗
第二种情况下,可以减少内存的消耗,但是不容易发现错误
Spring的bean中的作用域scope
分为singleton、prototype、request、session、global session
默认scope的值是singleton,产生的对象是单例的
在applicatonContext.xml配置:
<!--
创建对象的第一种方式:利用无参构造器
id:唯一标识符
class:类的全类名
-->
<bean id="helloIoc" class="com.rzjt.ioc.HelloIoc" scope = "singleton"></bean>
验证
public class App {
public static void main( String[] args ){
//启动 spring 容器
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloIoc helloIoc1 = (HelloIoc) context.getBean("helloIoc");
HelloIoc helloIoc2 = (HelloIoc) context.getBean("helloIoc");
System.out.println(helloIoc1.equals(helloIoc2)); // true
context.close();
}
}
scope = "prototype"多例模式,并且spring容器启动的时候并不会创建对象,而是在得到 bean 的时候才会创建对象
在applicatonContext.xml配置:
<!--
创建对象的第一种方式:利用无参构造器
id:唯一标识符
class:类的全类名
-->
<bean id="helloIoc" class="com.rzjt.ioc.HelloIoc" scope = "prototype"></bean>
验证
public class App {
public static void main( String[] args ){
//启动 spring 容器
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloIoc helloIoc1 = (HelloIoc) context.getBean("helloIoc");
HelloIoc helloIoc2 = (HelloIoc) context.getBean("helloIoc");
System.out.println(helloIoc1.equals(helloIoc2)); // false
context.close();
}
}
总结:在单例模式下,启动spring容器,便会创建对象;在多例模式下,启动容器并不会创建对象,获得bean的时候才会创建对象
Spring 容器生命周期
创建SpringLifeCycle.java
public class SpringLifeCycle{
public SpringLifeCycle(){
System.out.println("SpringLifeCycle");
}
public void init(){
System.out.println("init...");
}
public void destroy(){
System.out.println("destroy...");
}
public void sayHello(){
System.out.println("say Hello...");
}
}
applicationContext.xml
<!-- 生命周期 -->
<bean id="springLifeCycle" class="com.rzjt.ioc.SpringLifeCycle" init-method="init" destroy-method="destroy"></bean>
测试:
public class App {
public static void main( String[] args ){
//启动 spring 容器
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
SpringLifeCycle hello = (SpringLifeCycle) context.getBean("springLifeCycle");
hello.sayHello();
context.close();
}
}
打印
SpringLifeCycle
init...
say Hello...
destroy...
总结:spring容器的声明周期
- spring容器创建对象
- 执行init方法
- 调用自己的方法
- 当spring容器关闭的时候执行destroy方法
注意:当scope为“prototype”时,调用close方法时是不会调用destroy方法的