热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Spring中Bean的注入方式详解

nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd

  首先,要学习Spring中的Bean的注入方式,就要先了解什么是依赖注入。依赖注入是指:让调用类对某一接口的实现类的实现类的依赖关系由第三方注入,以此来消除调用类对某一接口实现类的依赖。

  Spring容器中支持的依赖注入方式主要有属性注入、构造函数注入、工厂方法注入。接下来将为大家详细介绍这三种依赖注入的方式以及它们的具体配置方法。

1.属性注入

  属性注入即通过setXXX( )方法注入bean的属性值或依赖对象。由于属性注入方式具有可选择性和灵活性高的特点,因此它也是实际开发中最常用的注入方式。

  Spring首先会调用bean的默认构造函数实例化bean对象,然后再通过反射的方法调用set方法来注入属性值。

  属性注入要求bean提供一个默认的构造函数,并且得为需要注入的属性提供set方法。

TIps:所谓默认的构造函数,即不带参数的构造函数。如果类中没有自定义任何构造函数,则系统(JVM)会自动生成一个不带参的默认构造函数,如果类中显式的自定义了有参数的构造函数,则系统就不会在自动生成默认构造函数,需要自己手动再加一个无参的构造函数。

  下面通过一个实例来演示Spring中bean的属性注入方式:

编写一个user类:

package com.Kevin.bean;
/**
 * 创建一个类测试bean的属性注入方式
 * @author Kevin
 *
 */
public class User {
   
    private String username;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }
   

}

配置文件:


    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:cOntext="http://www.springframework.org/schema/context" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

   
   
       
            Kevin
       

   

   

  其中,每个属性值对应一个property标签,name属性值为类中属性的名称。在bean实现类中拥有与其对应的实现方法setUsername( )。

  Tips:Spring只会检查bean中是否含有setter方法,而对是否有对应的属性变量则不作具体要求,但按照约定俗成的规则我们最好为其设定相应的属性变量。

  Spring中标签的命名规范:

  Spring的标签所指定的属性名称和bean实现类的setter方法满足Sun JavaBean的属性命名规范,即XXX的属性对应setXXX( )的方法。

  一般情况下,java的属性变量名都以小写字母开头,但考虑到一些特殊意义的英文缩略词,java bean也允许一些大写字母开头的变量名。但必须满足以下两点:

  • 变量的前两个字母要么全部大写,要么全部小写;
  • 但以一般编程习惯来说,属性名最好全部使用小写字母,方便编程和阅读。

  对于属性注入方式来说,只能人为的在配置文件中提供保证,而无法在语法级别提供保证。此时就需要使用构造函数注入这种方式,以此来更好的满足要求。

2.构造函数注入

  构造函数注入是除属性注入之外的另一种常用的注入方式,它可以保证一些必要的属性在bean实例化时就得到了设置,并在实例化后就可以使用。

  使用构造函数注入的前提是:bean必须提供带参的构造函数。

  对于构造函数的注入,配置文件可以有以下几种方式:

  • 按类型匹配入参
  • 按索引匹配入参
  • 联合使用类型和索引匹配入参
  • 通过自身类型反射匹配入参

【按类型匹配入参方式】

编写bean代码:

package com.Kevin.bean;
/**
 * 编写bean测试按类型匹配入参方式
 * @author Kevin
 *
 */

public class Person {
   
    private String name;
    private Integer age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
   

}

编写配置文件:


    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:cOntext="http://www.springframework.org/schema/context" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

   
   
       
            Kevin
       

       
            20
       

   

   

  Spring的配置文件采用和元素标签顺序无关的配置策略,因此可以在一定程度上保证配置信息的确定性。

  那么当bean中的构造函数的多个类型参数一样时,按照类型匹配入参的这种方式容易产生混淆,此时就需要使用另一种方式:按照索引匹配入参。

【按照索引匹配入参】

编写bean代码:

package com.Kevin.bean;
/**
 * 编写bean测试按照索引方式入参
 * @author Kevin
 *
 */

public class Student {
    private String name;
    private String gender;
    private Double score;
    public Student(String name, String gender, Double score) {
        super();
        this.name = name;
        this.gender = gender;
        this.score = score;
    }
   

}

配置文件编写如下:


    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:cOntext="http://www.springframework.org/schema/context" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

   
   
       
       
       
   

   


Tips:在属性注入时,Spring按java bean的规范确定配置属性和对应的setter方法,并使用java反射机制调用属性的setter方法完成属性注入。但java反射机制并不会记住构造函数的入参名,因此我们不能通过制定构造函数的入参名称来进行构造函数的配置,所以我们只能通过入参的类型及索引来间接完成构造函数的属性注入。

【联合使用类型和索引匹配入参】

  在某些复杂的配置文件当中,需要使用type和index同时出马才能完成构造函数的参数注入。下面使用一个实例来演示。

编写bean:

package com.Kevin.bean;
/**
 * 编写bean测试联合使用类型和索引匹配入参
 * @author Kevin
 *
 */

public class Teacher {
    private String name;
    private String address;
    private double salary;
    private int age;
    public Teacher(String name, String address, double salary) {
        super();
        this.name = name;
        this.address = address;
        this.salary = salary;
    }
    public Teacher(String name, String address, int age) {
        super();
        this.name = name;
        this.address = address;
        this.age = age;
    }
   

}

  在这个类中,有两个重载的构造函数,他们都有三个参数,在这种情况下使用type和index的方法都不能完成要求,这时候就需要他们两个属性同时使用了。

配置文件:


    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:cOntext="http://www.springframework.org/schema/context" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

   
   
       
            Kevin
       

       
            China
       

       
            20
       

   

   

  可以看到其实重点在于第三个入参的类型,所以我们在配置文件中指定了索引和类型,这样便可以使得Spring知道对哪个构造函数进行参数注入了。

  Tips:加入我们得配置文件中存在歧义问题,Spring容器是可以正常启动的,并不会报错,它将随机采用一个匹配的构造函数实例化bean。而随机选择的构造函数可能并不是用户所需要的,所以我们在编程时要小心避免出现这种歧义情况。

【通过自身类型反射匹配入参】

  如果bean构造函数入参的类型是可辨别的,由于java反射机制可以获取构造函数入参的类型,即使构造函数的注入不提供类型和索引的信息,Spring依旧可以完成构造函数信息的注入。例如下面实例中Manager类的构造函数的入参类型就是可以辨别的。

编写Manager类:

package com.Kevin.bean;
/**
 * 编写Bean测试通过自身类型反射匹配入参方式
 * @author Kevin
 *
 */

public class Manager {
    private String name;
    private Double salary;
    private Person person;
    public Manager(String name, Double salary, Person person) {
        super();
        this.name = name;
        this.salary = salary;
        this.person = person;
    }
   

}

编写配置文件:


    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:cOntext="http://www.springframework.org/schema/context" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

   
   
       
            Kevin
       

       
           
       

       
           
       

   

   

  以上几种方法都可以实现构造函数参数的注入,但是为了避免问题的发生,还是建议使用显式的index和type来配置构造函数的入参信息。

3.工厂方法注入

  工厂方法是应用中被经常使用的设计模式,也是控制反转和单实例设计思想的主要实现方法。工厂类负责创建一个或多个工厂类实例,工厂类方法一般以接口或抽象类变量的形式返回目标类实例。

  工厂类对外屏蔽了目标类的实例化步骤,调用者甚至根本不用指定具体的目标类是什么。由于Spring容器以框架的方法提供工厂方法的功能,并以透明的方式开放给开发者。因此很少需要手工编写工程方法。但在一些遗留系统或第三方类库中还是会碰到工程方法,此时便可以使用Spring工厂注入的方法来进行Spring的注入。

  Spring工厂注入的方法可以分为静态和非静态两种。

【非静态工厂方法】

  有些工厂方法是非静态的,必须实例化工厂类之后才能调用工厂方法。下面通过一个实例来演示。

编写工厂类:

package com.Kevin.factorybean;
/**
 * 编写工厂类测试非静态工厂方法注入
 * @author Kevin
 *
 */

public class BookFactory {
    public Book buyBook(){
        Book book = new Book();
        book.setName("Think in Java");
        return book;
    }

}

配置文件编写:


    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:cOntext="http://www.springframework.org/schema/context" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

   
   
   
   

  由于bookFactory的工厂方法不是静态的,因此需要先定义一个工厂类的bean,然后通过factory-bean属性来引用工厂bean实例。再通过属性factory-method来指定对应的工厂方法。

【静态工厂方法】

  很多工厂类方法都是静态的,这意味着无需创建工厂类实例的情况下就可以调用工厂类方法。因此静态工程方法比非静态工厂方法的调用更加方便简洁。下面通过一个实例来演示静态工厂方法。

编写factory类:

package com.Kevin.factorybean;
/**
 * 编写工厂类测试静态工厂方法注入
 * @author Kevin
 *
 */

public class CarFactory {
    public static Car createCar(){
        Car car = new Car();
        car.setBrand("Lamborghini");
        return car;
    }

}

编写配置文件:


    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:cOntext="http://www.springframework.org/schema/context" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

   
   
   

总结

  Spring提供了三种可供选择的注入方式,但在实际应用中,我们究竟该选择哪种注入方式,并没有统一的标准,如下是一些可以参考的理由:

  构造函数注入理由:

  • 构造函数保证重要属性预先设置;
  • 无需提供每个属性的setter方法,减少类的方法个数;
  • 可以更好地封装类变量,避免外部错误调用。

  属性注入理由:

  • 属性过多时,构造函数变的臃肿;
  • 构造函数注入灵活性不强,有时需要为属性注入null值;
  • 多个构造函数时,配置上产生歧义,复杂度升高;
  • 构造函数不利于类的继承和扩展;
  • 构造函数注入会引起循环依赖的问题。

  其实Spring为我们注入参数提供了这么多方法,那么这些方法必然有他们存在的道理,每个方法在某一问题上会有独特的优势,我们只需要按照我们具体的使用需求选择适合的方法来使用就好了,但一般不太推荐工厂方法注入。


推荐阅读
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Python语法上的区别及注意事项
    本文介绍了Python2x和Python3x在语法上的区别,包括print语句的变化、除法运算结果的不同、raw_input函数的替代、class写法的变化等。同时还介绍了Python脚本的解释程序的指定方法,以及在不同版本的Python中如何执行脚本。对于想要学习Python的人来说,本文提供了一些注意事项和技巧。 ... [详细]
  • 本文介绍了在Win10上安装WinPythonHadoop的详细步骤,包括安装Python环境、安装JDK8、安装pyspark、安装Hadoop和Spark、设置环境变量、下载winutils.exe等。同时提醒注意Hadoop版本与pyspark版本的一致性,并建议重启电脑以确保安装成功。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 本文介绍了Linux Shell中括号和整数扩展的使用方法,包括命令组、命令替换、初始化数组以及算术表达式和逻辑判断的相关内容。括号中的命令将会在新开的子shell中顺序执行,括号中的变量不能被脚本余下的部分使用。命令替换可以用于将命令的标准输出作为另一个命令的输入。括号中的运算符和表达式符合C语言运算规则,可以用在整数扩展中进行算术计算和逻辑判断。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • Python爬虫中使用正则表达式的方法和注意事项
    本文介绍了在Python爬虫中使用正则表达式的方法和注意事项。首先解释了爬虫的四个主要步骤,并强调了正则表达式在数据处理中的重要性。然后详细介绍了正则表达式的概念和用法,包括检索、替换和过滤文本的功能。同时提到了re模块是Python内置的用于处理正则表达式的模块,并给出了使用正则表达式时需要注意的特殊字符转义和原始字符串的用法。通过本文的学习,读者可以掌握在Python爬虫中使用正则表达式的技巧和方法。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 原文地址:https:www.cnblogs.combaoyipSpringBoot_YML.html1.在springboot中,有两种配置文件,一种 ... [详细]
  • 笔记day2 ... [详细]
  • 开发笔记:Java是如何读取和写入浏览器Cookies的
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Java是如何读取和写入浏览器Cookies的相关的知识,希望对你有一定的参考价值。首先我 ... [详细]
author-avatar
爱你116564
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有