返回顶部
首页 > 资讯 > 后端开发 > Python >基于SpringIOC创建对象的四种方式总结
  • 399
分享到

基于SpringIOC创建对象的四种方式总结

2024-04-02 19:04:59 399人浏览 独家记忆

Python 官方文档:入门教程 => 点击学习

摘要

我们平时创建对象的方式无非就是以下两种: 有参构造 、无参构造 我们来看看在spring中怎么处理这两种情况 首先我们先创建一个实体类: package com.MLXH.poj

我们平时创建对象的方式无非就是以下两种:

有参构造 、无参构造

我们来看看在spring中怎么处理这两种情况

首先我们先创建一个实体类:


package com.MLXH.pojo;
public class User {
    private String name;
    private String sex;
    private int age;
    public User() {
        System.out.println("User的无参构造");
    }
    public User(String name) {
        System.out.println("User的有参构造");
        this.name = name;
    }
    public User(String name, int age) {
        System.out.println("User的第二种有参构造");
        this.name = name;
        this.age = age;
    }
    public User(String name, String sex, int age) {
        System.out.println("User的第三种有参构造");
        this.name = name;
        this.sex = sex;
        this.age = age;
    }
    public void setName(String name) {
        System.out.println(name);
        this.name = name;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Spring创建对象的方式:

通过有参构造

  • 通过下标
  • 通过参数名 【推荐】
  • 通过参数类型

通过无参构造

  • 默认会用无参构造

注意点:实体类中一定要有一个无参构造方法

接下来我们看一下Spring是如何装配这些对象的:


<?xml version="1.0" encoding="UTF-8"?>
<!--suppress SpringFacetInspection -->
<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.MLXH.pojo.User">
    </bean>
    <!--无参构造,执行set方法-->
    <bean id="user1" class="com.MLXH.pojo.User">
        <property name="name" value="寒雪1"/>
    </bean>
    <!--使用构造器的参数下标进行赋值-->
    <bean id="user2" class="com.MLXH.pojo.User">
        <constructor-arg index="0" value="寒雪2"/>
        <constructor-arg index="1" value="18"/>
    </bean>
    <!--通过名字进行赋值-->
    <bean id="user3" class="com.MLXH.pojo.User">
        <constructor-arg name="name" value="寒雪3"/>
        <constructor-arg name="age" value="3"/>
    </bean>
    <!--通过类型进行赋值-->
    <bean id="user4" class="com.MLXH.pojo.User">
        <constructor-arg type="java.lang.String" value="寒雪4"/>
        <constructor-arg type="java.lang.Integer" value="18"/>
        <constructor-arg type="java.lang.String" value="男"/>
    </bean>
</beans>

测试


package com.MLXH.pojo;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UserTest {
    @Test
    public void test1(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        User user = (User)context.getBean("user1");
        System.out.println(user.toString());
    }
    @Test
    public void test2(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        User user = (User) context.getBean("user2");
        System.out.println(user);
    }
    @Test
    public void test3(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        User user = (User) context.getBean("user3");
        System.out.println(user);
    }
}

结果:运行第一个测试类的结果:

在这里插入图片描述

分析:我们针对输出的结果进行分析,我们拿到的是user1对象,那么为什么会输出这么多的语句呢?

原因是我们执行了spring的配置文件bean.xml的全部内容,当执行


ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

语句时,会加载beans.xml中的全部内容,因此其中所有的装配信息都会进行加载,会按照我们装配的顺序进行加载。

注意:


<bean id="user1" class="com.MLXH.pojo.User">
        <property name="name" value="寒雪1"/>
</bean>

看似像是执行了有参构造,但其实是执行了无参构造,然后通过set方法将,name赋值进去的…就像是执行了这样的代码:


User user1 = new User();
user1.setName="寒雪1";

这只是执行了Test1的,其他的类似…

Springioc——控制反转中创建对象的细节

在刚开始使用Java的时候,创建对象的方式多半是使用 new+对应的构造方法,为了进一步提高对象的安全性和降低耦合,开始使用工厂模式和单例模式,通过调用工厂里的方法获取对象,再后来通过反射加配置文件的方式,在创建对象的过程中进一步降低耦合。

那么SpringIOC里创建对象的过程是怎样的呢?具体来说:SpringIOC是什么时候创建对象的?通过哪种方法创建的对象?创建的对象是单例的还是多例的?创建的对象是由谁来保管和控制的?

这些问题不仅仅是Spring需要考虑的,而且是程序员应该考虑的,我们创建对象的效率和对内存的使用率很大程度上影响到开发代码的优劣性。

接下来,我们就通过Spring创建对象的过程,一步步来讨论一下Spring框架IOC组件部分,创建对象的细节。

一、Spring创建对象的过程(在此之前我们已经配置好了Spring的配置文件)

启动spring容器(根据Spring配置文件不同创建不同的Spring容器)


//启动spring容器(根据Spring配置文件不同创建不同的Spring容器)
ApplicationContextcontext =
newClassPathXmlApplicationContext(
"resources/spring_ioc.xml");

这里实现的步骤如下:

1.读取resources文件下spring_ioc.xml

2.Xml解析spring_ioc.xml

3.把解析xml里的内容存储到内存的map集合

4.从map集合中读取集合内容,就是<Bean></Bean>清单里的内容

5.遍历集合中的所有数据,并反射实例化对象


Class.forName(“com.spring.ioc.Hello”).newInstance()

从容器中取出对象,以及使用对象


//从spring容器中获取对象hello
Hello hello = (Hello)context.getBean("Hello");
//使用hello对象调用sayHello方法
hello.sayHello();

以上关键的两个环节中,需要重点理解的是spring容器为什么能创建保管对象,因为Spring在初始化的时候,就将Bean 里的属性调入放入到一个map集合中区维护了,这个map集合的key=”id”,value=”object” (反射实例化的对象),spring容器在底层就相当于这个map<id,object>,而Bean就被存放在这个map中。

当我们把spring容器启动好以后,也就是context对象创建完成后,通过调用context对象里的getBean()方法来从map中用key寻找value,从而获取对象。

细化分析:启动Spring容器时,将Bean存储到Map集合中,需要调用反射来实例化Bean中封装的类路径,那么xml配置文件中每存储一个不同的Bean,就会实现一次反射,产生一个实例对象,也就是说,Spring容器中产生的对象仅和xml配置文件相关,与取出对象操作无关,Spring可以实例化一个类多次(<Bean/>中id不同,class相同),也可以只实例化一个类一次,但多次调用。单例的创建时间是在Spring容器启动时。

二、创建对象的四种方式

由上我们知道Spring底层是通过反射来创建对象的,那我们在创建类的时候,可以创建实体类,抽象类,接口等等,spring底层反射到底使用什么方法来创建对象呢?这就需要考虑我们是创建什么对象了。

1. 无参构造

反射是通过无参构造来实例化类的,所以,如果我们创建一个实体类,并想将类产生的实例放到spring容器中,必须保证这个类有无参构造。当这个类中未写构造器时,java编译器会在编译时自动添加一个无参构造,但是如果这个类中有含参构造时,只能通过人工添加无参构造来实现反射,这一点在以后的开发设计中要牢记。

2. 静态工厂设计模式

那抽象类怎么实例化呢?抽象类无法直接实例化,只能通过添加静态工厂的方式,在工厂中添加静态方法返回抽象类的getInstance()方法,从而获取实例对象。

这时,我们需要一个抽象类,一个工厂类,而且xml中的配置文件也需要发生变化,<Bean>中class类的加载路径需要指定为工厂类,而且需要指定新的属性为:factory-method=”get抽象类的实例对象方法”。

例:我们需要用util包下的Calendar这个抽象日期类。

静态工厂代码为:


        package staticfactory;
        import java.util.Calendar;
        public class StaticFactory {
               public static Calendar getCalendar(){
                      return Calendar.getInstance();
               }
         }

Xml文件中的Bean应该修改成:


<bean id="cal" class="staticfactory.StaticFactory" factory-method="getCalendar"/>

测试可使用:双击test2方法右键run as》JUnit得到当前电脑的系统时间。


@Test
publicvoid test2(){
      //启动spring容器
     ApplicationContextcontext =
     newClassPathXmlApplicationContext("staticfactory/applicationContext.xml");
     Calendar calendar = (Calendar)context.getBean("cal");
     System.out.println(calendar.getTime());
}

无法直接实例化的类就可以使用静态工厂法。

此时Spring中并未创建工厂这个类,而是根据<Bean/>中的factory—method属性,直接调用工厂的getCalendar静态方法,产生的实例只有一个,就是工厂中,getCalendar静态方法通过调用Calendar.getInstance()方法产生的实例。

3. 实例工厂设计模式

静态工厂设计模式不会创建工厂类对象,而是直接调用静态工厂的静态方法。而工厂方法设计模式会创建类,然后通过xml中配置去访问其方法。

例:同样是需要Calendar这个抽象类


package methodfactory;
import java.util.Calendar;
public class MethodFactory {
       publicMethodFactory() {
      System.out.println("如果创建工厂类的实例,必定会打印这句话!");
       }
       publicCalendar getCalendar(){
      returnCalendar.getInstance();
       }
}

Xml中的配置由一个变为两个(这也证明了上述结论,配置文件中<Bean/>的个数影响产生的实例对象的个数)


<bean id="methodFacotry" class="methodfactory.MethodFactory"/>
<bean id="cal" factory-bean="methodFacotry"  factory-method="getCalendar"/>

测试可使用:双击test2方法右键run as》JUnit得到当前电脑的系统时间。


@Test
public void test(){
//启动spring容器
ApplicationContext context =
newClassPathXmlApplicationContext("methodfactory/applicationContext.xml");
Calendar calendar = (Calendar)context.getBean("cal");
System.out.println(calendar.getTime());
}

输出结果为上述打印的那句话和系统时间,两个<Bean/>产生两个实例对象。

4. Spring工厂设计模式

这是Spring框架自身提供的工厂,它需要实现FactoryBean接口,实现代码就必须写在getObject()方法中。Spring工厂实现一个接口就可以了,简单方便。

例:

创建SpringFactory类实现FactoryBean接口,定义泛型<Calendar>


package springfactory;
import java.util.Calendar;
import org.springframework.beans.factory.FactoryBean;
public class SpringFactory implements FactoryBean<Calendar>{
public SpringFactory() {
System.out.println("我是一个spring工厂类");
}
               
public Calendar getObject()throws Exception {
return Calendar.getInstance();
}
               
public Class<?> getObjectType() {
return Calendar.class;
}
               
public boolean isSingleton() {
return false;
}
}

配置xml文件中的Bean元素:


<bean id="cal"class="springfactory.SpringFactory"/>

测试可使用:双击test3方法右键run as》JUnit得到当前电脑的系统时间。


@Test
public void test3(){
//启动spring容器
ApplicationContext context =
newClassPathXmlApplicationContext("springfactory/applicationContext.xml");
Calendar calendar = (Calendar)context.getBean("cal");
System.out.println(calendar.getTime());
}

三、Spring创建对象是单例还是多例?+懒加载

单例就是指在在Spring容器中的对象只有一个,每次从spring容器中取出不会产生新的对象。

多例就是每次从Spring容器中取出对象的时候会产生新的对象,内存中存在多个对象。

默认情况下,spring中创建的对象都是单例,并且维护其生命周期。单例对象的生命周期与spring容器共命运,同生共死。

但如果对象是多例的,那么Spring容器只负责对象的创建,不负责维护其生命周期,也就是说如果容器关闭,对象并未销毁,需要用户自行关闭。

具体实现代码是在Bean标签中插入属性


 
<bean id="Hello" class="com.spring.ioc.Hello"scope="prototype"/>

Scope属性代表了spring创建对象是单例还是多例。

那么单例多例各有什么优缺点呢?

单例的好处就是,spring创建后,那就不会再频繁创建,缓存在map中,省内存。坏处,对象里的数据不安全,即线程不安全

多例的好处就是随时用随时创建,线程安全,缺点是占用内存。

单例多例各有各的特点,思考一个问题,如果Spring容器中要使用很多次单例,那么单例是不是丧失了它的优势呢?即使没有业务调用这些对象,这些对象依然在spring容器加载的时候产生,不仅仅浪费了容器的容量,还延长了加载时间,这时候我们就需要用懒加载,堆单例模式进行改造了。

首先我们可以在全局配置(第一个<Bean/>)中添加default-lazy-init="true",这样就默认使用懒加载。

或者在单例的配置中添加:


<bean id="Hello"class="com.spring.ioc.Hello" scope="singleton"lazy-init="true"/>

另外,多例模式都是懒加载,当多例模式的懒加载被设置为false时,会报错!

四、对象的创建和保管(初始化+销毁)

Spring 容器执行过程

1.new Instance----调用构造方法创建对象

2.Init-method------执行初始化方法

3.对象调用方法。

4.容器关闭,执行销毁方法 ,如果scope=”property”时让其不负责对象的销毁

总结

通过对Spring内对象产生的细节进行探究,了解Spring底层创建实例的方式,通过熟练使用这些方式,掌握对Spring框

架的理解,这样对程序员的自我成长是很好的~

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

--结束END--

本文标题: 基于SpringIOC创建对象的四种方式总结

本文链接: https://lsjlt.com/news/128654.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 基于SpringIOC创建对象的四种方式总结
    我们平时创建对象的方式无非就是以下两种: 有参构造 、无参构造 我们来看看在Spring中怎么处理这两种情况 首先我们先创建一个实体类: package com.MLXH.poj...
    99+
    2024-04-02
  • 6种Java创建对象的方式总结
    目录1. 使用new关键字2. 使用Class的newInstance()方法3. 使用Constructor的newInstance()方法4. 使用clone()方法5. 使用反...
    99+
    2023-05-18
    Java创建对象方式 Java创建对象
  • JS创建对象的四种方式
    目录1.通过字面量的方式去创建对象2.使用new字符创建对象3.自定构造函数创建对象4.工厂模式创建对象创建对象的4种方式: 1.字面量的方式去创建对象 2.使用n...
    99+
    2024-04-02
  • 基于sqlserver的四种分页方式总结
    第一种:ROW_NUMBER() OVER()方式 select * from (     select *, ROW_NUMBER() OVER(Order by ArtistId ...
    99+
    2024-04-02
  • Java线程创建的四种方式总结
    多线程的创建,方式一:继承于Thread类 1.创建一个继承于Thread类的子类 2.重写Thread类的run()--->将此线程执行的操作声明在run()中 3.创建Th...
    99+
    2024-04-02
  • Java创建随机数的四种方式总结
    目录c语言随机数java1.Random2.SecureRandom3.ThreadLocalRandom4.Math.Random完整代码第一次接触到随机数还是在c语言里面 使用的...
    99+
    2024-04-02
  • JavaScript对象的四种创建方法
    目录前言1. 基于对象字面量2. 利用new Object方式创建对象3. 基于构造函数4. 基于工厂方法前言 今天我们来学习一下JavaScript中关于对象的四种创建方法。 首先...
    99+
    2024-04-02
  • Java中创建对象的6种方式
    目录背景创建对象的 6 种方式方法1:new 一个对象方法2:克隆一个对象方法3:类派发一个对象(反射)方法4:动态加载一个对象(反射)方法5:构造一个对象(反射)方法6:反序列化一...
    99+
    2024-04-02
  • Spring IOC创建对象的两种方式
    IOC创建对象的方式 一、 使用无参构造创建对象(默认方式) 创建实体类 注意:属性必须要有set方法,来完成注入 public class User { private S...
    99+
    2024-04-02
  • Java中创建对象的5种方式
    作为Java开发者,我们每天创建很多对象,但我们通常使用依赖管理系统,比如Spring去创建对象。然而这里有很多创建对象的方法,我们会在这篇文章中学到。Java中有5种创建对象的方式,下面给出它们的例子还有它们的字节码使用new关键字} →...
    99+
    2023-06-03
  • js 创建对象的多种方式与优缺点小结
    目录早期创建方式工厂模式构造函数模式构造函数模式优化原型模式构造函数和原型模式组合动态原型模式寄生构造函数模式稳妥构造函数模式早期创建方式 var obj = new Objec...
    99+
    2024-04-02
  • Java各种比较对象的方式的对比总结
    一、==和!=操作符 让我们从==和!=开始可以分别判断两个Java对象是否相同的操作符。 1.1 原始类型(Primitives) 对于原始类型,相同意味着具有相等的值: as...
    99+
    2024-04-02
  • java创建对象的方式有哪几种
    在Java中,可以通过以下几种方式创建对象:1. 使用new关键字:通过使用new关键字,可以调用类的构造方法实例化一个对象。例如:...
    99+
    2023-10-10
    java
  • 比较JavaScript对象的四种方式
    目录前言引用比较手动比较浅层比较深层比较总结前言 比较JavaScript中的原始值非常简单。只需使用任何一种可用的相等运算符即可,例如严格相等运算符: 'a' === 'c';...
    99+
    2024-04-02
  • eclipse创建springboot项目的三种方式总结
    目录方法一安装STS插件新建spring boot项目项目启动方法二1.创建Maven项目2.选择项目类型3.选择项目4.编写项目组和名称-finish即可5.修改pom.xml文件...
    99+
    2024-04-02
  • IDEA创建Vue项目的两种方式总结
    目录安装好Vue运行环境1、下载安装Node.js2、安装打包工具webpack创建Vue项目1、命令行方式(推荐)2、使用Vue模板总结安装好Vue运行环境 1、下载安装Node....
    99+
    2023-05-14
    IDEA创建Vue项目 IDEA创建Vue IDEA创建Vue方式
  • mysql表的四种分区方式总结
    目录1、什么是表分区?2、表分区与分表的区别3、表分区有什么好处?4、分区表的限制因素5、如何判断当前MySQL是否支持分区? 6、MySQL支持的分区类型有哪些?6.1、...
    99+
    2024-04-02
  • Spring复杂对象创建的方式小结
    在Spring中,对于简单类型的创建,我们可以使用set注入和构造注入。但是对于复杂类型的如何创建? 什么是复杂类型,比如连接数据库的Connection对象,以及Mybatis中的...
    99+
    2024-04-02
  • .NET中创建对象的几种方式和对比
    目录使用标准反射的 Invoke 方法使用 Activator.CreateInstance 使用 Microsoft.Extensions.DependencyInjection ...
    99+
    2024-04-02
  • 关于java中创建线程的方式的总结
    继承Thread类public class ThreadCreator extends Thread{ public static void main(String[] args) { //第一种方式: ...
    99+
    2014-08-21
    java入门 java 创建 线程 方式 总结
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作