Spring 框架学习---- IOC创建对象

Posted RAIN 7

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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默认创建对象都是单例模式的,一个类只能拿到一个实例

以上是关于Spring 框架学习---- IOC创建对象的主要内容,如果未能解决你的问题,请参考以下文章

Spring框架学习笔记

Spring框架学习-Spring和IOC概述

Spring学习总结——Spring实现IoC的多种方式

学习笔记--Spring框架

spring 学习 AOP和IOC

Java Spring 框架初步学习总结简单实现 IoC 和 AOP