• 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"));
    
    • 1

    ApplicationContext


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


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


    1)ClassPathXmlApplicationContext(重点认识)

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

    ApplicationContext applicationContext = new ClassPathXmlApplicationContext(String configLocation);
    
    • 1

    2)FileSystemXmlApplicationContext(知道就行)

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

    ApplicationContext applicationContext = new FileSystemXmlApplicationContext(String configLocation);
    
    • 1

      在使用 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 + '\'' +
                    '}';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    (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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    (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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

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

    在这里插入图片描述


    我们可以得到一个结论:

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


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


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


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


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

    在这里插入图片描述

    <bean id="exampleBean" class="examples.ExampleBean">
        <constructor-arg index="0" value="7500000"/>
        <constructor-arg index="1" value="42"/>
    </bean>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 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("三个参数构造进行创建对象");
        }
    
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    (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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

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

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

    (4)运行结果

    在这里插入图片描述

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

    在这里插入图片描述

    <bean id="exampleBean" class="examples.ExampleBean">
        <constructor-arg type="int" value="7500000"/>
        <constructor-arg type="java.lang.String" value="42"/>
    </bean>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    (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>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    查看运行结果

    在这里插入图片描述


    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;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    (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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    (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);
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    (4)运行结果

    在这里插入图片描述


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

  • 相关阅读:
    分布式事务理论和解决方案
    数据机房中智能小母线与列头柜方案的对比与分析
    【TeamViewer丨远程控制软件】上海道宁助您远程访问和即时远程支持,提高远程工作团队的生产力
    redis-集群-2-哨兵模式
    结合双向LSTM和注意力机制的DQN-CE算法船舶能量调度
    得帆信息副总裁——孔金:低代码在医药行业的应用实践
    Python应该如何系统的自学?(零基础入门必看)
    记录tomcat-9.0.65在apr模式下无法通过IP访问问题排查和处理
    开机启动流程及营救模式
    JS 数组 splice 用法
  • 原文地址:https://blog.csdn.net/rain67/article/details/125308077