Spring 框架学习(三)---- IOC创建对象

Spring 框架学习(三)---- IOC创建对象的方式


  写完了第一个Spring的程序,相信已经对spring已经有所了解了,那么我们这节来了解一下,IOC是如何创建对象,什么时候创建对象的。


1、IOC 什么时候创建对象?


  Spring 提供了两种 IoC 容器,分别为 BeanFactory 和 ApplicationContext

我们先对两种进行介绍一下


BeanFactory(不推荐使用)


  BeanFactory 是基础类型的 IoC 容器,简单来说,BeanFactory 就是一个管理 Bean的工厂,它主要负责初始化各种 Bean,并调用它们的生命周期方法。


  BeanFactory 接口有多个实现类,最常见的是 XmlBeanFactory类,它是根据 XML 配置文件中的定义装配 Bean 的。


  创建 BeanFactory 实例时,需要提供 Spring 所管理容器的详细配置信息,这些信息通常采用 XML 文件形式管理。其加载配置信息的代码具体如下所示

BeanFactory beanFactory = new XmlBeanFactory(new FileSystemResource("D://applicationContext.xml"));

ApplicationContext


  ApplicationContext 是 BeanFactory 的子接口,也被称为应用上下文,它不仅提供了 BeanFactory 的所有功能,还添加了对 i18n(国际化)、资源访问、事件传播等方面的良好支持。


  ApplicationContext 接口有两个常用的实现类,具体如下。


1)ClassPathXmlApplicationContext(重点认识)

  该类从类路径 ClassPath 中寻找指定的 XML 配置文件,找到并装载完成 ApplicationContext 的实例化工作,具体如下所示。

ApplicationContext applicationContext = new ClassPathXmlApplicationContext(String configLocation);

2)FileSystemXmlApplicationContext(知道就行)

  该类从指定的文件系统路径中寻找指定的 XML 配置文件,找到并装载完成 ApplicationContext 的实例化工作,具体如下所示。

ApplicationContext applicationContext = new FileSystemXmlApplicationContext(String configLocation);

  在使用 Spring 框架时,可以通过实例化其中任何一个类创建 Spring 的 ApplicationContext 容器。


两者区别


BeanFactory

  BeanFactory在启动的时候不会去实例化Bean,中有从容器中拿Bean的时候才会去实例化;


ApplicationContext

  ApplicationContext在启动的时候就把所有的Bean全部实例化了。

  所以我们可以得知,对象在什么时候创建,我们使用的是ApplicationContext,所以在Spring启动的时候就已经把所有的Bean对象给创建好了。


优缺点,各有利弊

  • 延迟实例化的优点:(BeanFactory)

先快后慢

  应用启动的时候占用资源很少;对资源要求较高的应用,比较有优势;


  • 不延迟实例化的优点: (ApplicationContext)

先慢后快

1.  所有的Bean在启动的时候都加载,在后续的操作中系统运行的速度快;

2.  在启动的时候所有的Bean都加载了,我们就能在系统启动的时候,尽早的发现系统中的配置问题


2、IOC 如何创建对象?


(1)我们给实体类中加了一个无参构造方法、还有带一个参数的构造方法。

package com.kuang.pojo;

public class Hello {
    private String str;

    public Hello() {
        System.out.println("这是一个无参构造!");
    }

    public Hello(String str) {
        this.str = str;
        System.out.println("这是一个带有一个参数的构造器!");
    }

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }

    @Override
    public String toString() {
        return "Hello{" +
                "str='" + str + '\'' +
                '}';
    }
}

(2)配置xml中的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">
    
    <bean id="hello" class="com.kuang.pojo.Hello">
        <property name="str" value="Hello Spring!"/>
    </bean>
</beans>

(3)编写业务层代码

package com.kuang.service;

import com.kuang.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


public class HelloService {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        Hello hello = context.getBean("hello", Hello.class);
        System.out.println(hello);
    }
}

运行之后,默认调用的是无参的构造方法

在这里插入图片描述


我们可以得到一个结论:

如果不做专门的配置,那么bean是通过无参构造来进行创建对象的


如果想要对实体类进行有参构造的创建怎么实现呢?


IOC创建有参构造器对象的三种方式


这三种方式同样,推荐大家一定要上spring的官方进行查看,说的非常清楚了。


(1)根据参数下标进行赋值(推荐)

在这里插入图片描述

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg index="0" value="7500000"/>
    <constructor-arg index="1" value="42"/>
</bean>

  • index 代表构造参数的下标,从0开始
  • value 代表设置的值

在文档中说明,通过index(从0开始),对对应位置的构造参数进行设置value,即可通过有参构造器构建对象


(1)写一个User类,中有四个构造函数,有参,一个构造参数…,

package com.kuang.pojo;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

@Getter
@Setter
@ToString
public class User {
    private int id;
    private String userName;
    private String password;

    public User() {
        System.out.println("无参构造进行创建对象!");
    }

    public User(int id) {
        this.id = id;
        System.out.println("一个参数构造的进行创建对象");
    }

    public User(int id, String userName) {
        this.id = id;
        this.userName = userName;
        System.out.println("两个参数构造进行创建对象");
    }

    public User(int id, String userName, String password) {
        this.id = id;
        this.userName = userName;
        this.password = password;
        System.out.println("三个参数构造进行创建对象");
    }


}

(2)xml文件通过下标的方式配置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">

 <bean id="user" class="com.kuang.pojo.User">
     <constructor-arg index="0" value="1"/>
 </bean>

</beans>

(3)然后通过ApplicationContext启动Spring容器

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        User user = context.getBean("user",User.class);
    }

(4)运行结果

在这里插入图片描述

(2)根据参数类型进行赋值(不推荐)

在这里插入图片描述

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg type="int" value="7500000"/>
    <constructor-arg type="java.lang.String" value="42"/>
</bean>

  • type 构造参数的类型,如果是普通类型直接写int、double,如果是引用类型写全限定名

  • value 设置的参数值

在文档中说明,通过type(引用类型要写全限定名),对对应类型的构造参数进行设置value,即可通过有参构造器构建对象

有一个问题,如果多个构造参数都是同一个类型呢?

答:会根据标签的顺序对同一类型的参数进行从前到后赋值。

(1)前面的User类不变

(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">

 <bean id="user" class="com.kuang.pojo.User">
     <constructor-arg type="int" value="1"/>
     <constructor-arg type="java.lang.String" value="userName"/>
     <constructor-arg type="java.lang.String" value="password"/>
 </bean>

</beans>

(3)启动Spring,如上

(4)查看运行结果

在这里插入图片描述


(3)根据参数名进行赋值(推荐)


在这里插入图片描述

<beans>
    <bean id="thingOne" class="x.y.ThingOne">
        <constructor-arg ref="thingTwo"/>
        <constructor-arg ref="thingThree"/>
    </bean>

    <bean id="thingTwo" class="x.y.ThingTwo"/>

    <bean id="thingThree" class="x.y.ThingThree"/>
</beans>

  • name 构造参数的类型,如果是普通类型直接写int、double,如果是引用类型写全限定名

  • value/ref 设置的参数值

这种方式看着非常直观,非常容易理解,这种方式与设置类中的属性是一样的

其他都不变,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">

 <bean id="user" class="com.kuang.pojo.User">
    <constructor-arg name="id" value="1"/>
     <constructor-arg name="userName" value="root"/>
     <constructor-arg name="password" value="123456"/>
 </bean>

</beans>

查看运行结果

在这里插入图片描述


3、IOC容器存储一个bean,取出多个对象是否相同?


(1)编写实体类User

package com.kuang.pojo;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
public class User {
    private int id;
    private String userName;
    private String password;

}

(2)在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">

 <bean id="user" class="com.kuang.pojo.User"/>

</beans>

(3)根据同一个bean取出多个对象

  public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        User user = context.getBean("user",User.class);
        User user2 = context.getBean("user",User.class);
        System.out.println(user==user2);

    }

(4)运行结果

在这里插入图片描述


结论: IOC默认创建对象都是单例模式的,一个类只能拿到一个实例

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

RAIN 7

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值