Spring 03: 依赖注入

如何描述控制反转与依赖注入?

  • 控制反转(IoC) 是 Spring Framework 的核心原则之一。IoC 使得对象的创建和管理不再由应用程序本身控制,而是由 Spring 容器控制。这种设计使得应用程序的组件之间的耦合度降低,提高了模块的独立性和可测试性。

  • 依赖注入(DI) 是 IoC 的一种实现方式,它允许 Spring 容器将所需的依赖自动注入到 Bean 中,而不是让 Bean 自行创建或查找依赖。这种方式减少了组件之间的硬编码依赖,使得应用程序更加灵活和可维护。

基于构造器的依赖注入

首先,为需要注入的依赖提供对应的构造器。然后,在XML中对<bean>标签增加子标签<construtor-arg>进行依赖注入。对于形参值的指定主要有几种方式:

  1. name
xml 复制代码
<bean id="bookService2" class="space.mora.service.impl.BookServiceImpl2">
	<constructor-arg name="userDao" ref="userDao"/>  
	<constructor-arg name="bookDao" ref="bookDao"/>
</bean>

注意: 此处的name是指形参名称,而非依赖的属性名称的。

  1. type
xml 复制代码
<bean id="bookService2" class="space.mora.service.impl.BookServiceImpl2">
	<constructor-arg type="java.lang.String" value="BOOK SERVICE #2"/>-->
	<constructor-arg ref="userDao"/>  
	<constructor-arg ref="bookDao"/>
</bean>

注意 :仅当每个类型的参数只有一个时方可使用。type若需指定引用类型名,需要给出该引用类的完全限定名。例如Stringjava.lang.String。此外,若使用ref引用其他bean,则Spring会自己判断依赖bean的类型,type可以省略。

  1. index
xml 复制代码
<bean id="bookService2" class="space.mora.service.impl.BookServiceImpl2">
	<constructor-arg index="0" value="12"/>
	<constructor-arg value="BOOK SERVICE #2">
	<constructor-arg ref="userDao"/>  
	<constructor-arg ref="bookDao"/>
</bean>

注意: 索引从0开始,表示所使用构造器的对应形参。index标志具有最高优先级,当有constructor-arg指定了index属性后,会先按照index将形参进行填充,剩余constructor-arg无论是否有nametype属性标识,其绝对位置随意,但相对顺序必须与形参列表一样。

举例:4个参数,0和2的constructor-arg使用index指定了,那么剩下两个如果不用index指定的话,其绝对位置可以随意在0和2的前后,但是相对顺序必须为先1后3。否则依赖会注入错误,或者干脆类型不匹配抛UnsatisfiedDependencyException异常。

基于setter的依赖注入

首先,为Bean类中需要注入的依赖提供set方法。然后,在XML中对<bean>标签增加子标签<property>进行依赖注入。对于引用类型依赖,使用ref属性引用其他bean;对于字面值类型的依赖,使用value设置具体值。

xml 复制代码
<bean id="bookDao" class="space.mora.dao.impl.BookDaoImpl"/>  
<bean id="userDao" class="space.mora.dao.impl.UserDaoImpl"/>  
<bean id="bookService1" class="space.mora.service.impl.BookServiceImpl">
	<property name="serviceName" value="BOOK SERVICE #1"/>
	<property name="connNum" value="15"/>
	<property name="bookDao" ref="bookDao"/>
	<property name="userDao" ref="userDao"/>
</bean>

请注意:value属性为""时,代表空字符串,若想设置为null,请采用:

java 复制代码
<bean ......>
	<property ......>
		<null/>
	</property>
</bean>

那么,依赖注入究竟选择构造器方式还是setter模式呢?参考黑马SSM教程

    1. 强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null
    2. 可选依赖使用setter注入进行,灵活性强
    3. Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
    4. 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入
    5. 实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
    6. 自己开发的模块推荐使用setter注入

自动注入(自动装配)

Spring容器可以通过检查 ApplicationContext 的内容,来自动处理Bean之间的依赖关系。通过XML配置中,<bean>标签的autorwire属性完成自动注入。该属性可选值有4种:

  1. no。默认情况下,不启用自动装配。
  2. byType。若容器配置中存在唯一类型Bean,则引用该Bean作为依赖。
  3. byName。若容器配置中存在id与装配目标成员属性名相同的Bean,则引用该Bean作为依赖。
  4. byConstructor。与byType类似,自动寻找类型与装配目标构造器形参列表类型相同的其他Bean作为依赖。
xml 复制代码
<bean id="bookDao" class="space.mora.dao.impl.BookDaoImpl"/>  
<bean id="userDao" class="space.mora.dao.impl.UserDaoImpl"/>

<!--    3. 自动装配 -->  
<!--    3.1 byType -->  
    <bean id="bookService3" class="BookServiceImpl3" autowire="byType"/>  
<!--    3.2 byName -->  
    <bean id="bookService3" class="BookServiceImpl3" autowire="byName"/>  
<!--    3.3 byConstructor-->  
    <bean id="bookService3" class="BookServiceImpl3" autowire="constructor"/>

请注意,仅Bean,即引用类型的依赖可以自动注入,而字面值类型不行。并且,构造器与setter注入方式会直接覆盖自动注入。

集合注入

示例,比较少用。

xml 复制代码
<bean id="bookService4" class="space.mora.service.impl.BookServiceImpl4">  
    <property name="array">  
        <array>  
            <value>10</value>  
            <value>20</value>  
        </array>  
    </property>  
    <property name="list">  
        <list>  
            <value>15</value>  
            <value>25</value>  
        </list>  
    </property>  
    <property name="set">  
        <set>  
            <value>cug</value>  
            <value>whu</value>  
        </set>  
    </property>  
    <property name="map">  
        <map>  
            <entry key="cug" value="211"/>  
            <entry key="whu" value="985"/>  
        </map>  
    </property>  
    <property name="properties">  
        <props>  
            <prop key="cug">211</prop>  
            <prop key="whu">985</prop>  
        </props>  
    </property>  
</bean>

Properties文件加载

<context:property-placeholder> 是 Spring Framework 中的一个 XML 配置标签,用于加载和解析外部属性文件,以便在 Spring 的应用上下文中使用这些属性。它通常用于在应用启动时加载配置文件中的属性,并将这些属性值注入到 Spring beans 中。

功能

  1. 属性加载<context:property-placeholder> 可以从指定的位置加载属性文件,支持类路径、文件系统路径等。
  2. 占位符解析 :在 Spring 配置文件中,你可以使用 ${property.name} 语法引用这些属性,Spring 会在运行时将这些占位符替换为属性文件中的实际值。
  3. 属性覆盖:如果多个属性文件中定义了相同的属性,后加载的文件中的属性值会覆盖先前加载的值。

使用方法

  1. 首先在<beans>标签中启用context命名空间
xml 复制代码
<beans xmlns="http://www.springframework.org/schema/beans"  
   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">
  1. 然后定义<context:property-placeholder>标签,通过location属性指定资产文件位置。
xml 复制代码
<context:property-placeholder location="classpath*:*.properties" system-properties-mode="NEVER"/>
  • location是必选的,具体语法可以参照下方小节
  • system-properties-mode(可选):用来定义系统属性(从Java系统环境获取的属性)如何与从属性文件加载的属性交互。这个属性可以设置为以下三个值之一:
    • NEVER**(默认值):不使用系统属性,占位符只会使用属性文件中的值。
    • FALLBACKSYSTEM_PROPERTIES_MODE_FALLBACK):如果在属性文件中找不到对应的属性,则会回退到系统属性。
    • OVERRIDESYSTEM_PROPERTIES_MODE_OVERRIDE):系统属性将始终覆盖属性文件中的同名属性,即使属性文件中存在这些属性。
  • 重名问题:如果加载的多个properties文件中有重名prop,那么后加载的将覆盖先加载的属性。
  1. 加载的属性可以在XML配置中以${propname}的形式使用。(当然也可以通过配置注入资源类以在Java代码中使用,这个暂不讨论)

context location相关语法

<context:property-placeholder>标签的location属性时,这个属性用来指定属性文件的位置,从而加载所需的配置。这里的语法非常关键,因为它定义了如何找到和读取这些属性文件。以下是关于location属性的一些详细解释和语法规则:

  1. 基本语法
    location属性可以接受一个或多个文件路径,这些路径可以是绝对的或相对的,并且可以包含Ant风格的通配符(如*?)。

  2. 路径类型

    • 本地文件系统路径 :可以直接使用文件系统的路径,如file:C:/config/myconfig.propertiesfile:/etc/config/myconfig.properties
    • 类路径资源 :使用classpath:前缀,表示文件位于类路径上,如classpath:config/myconfig.properties
    • 通配符支持 :使用classpath*:前缀加通配符支持从所有类路径(包括JAR文件)中加载匹配的资源,如classpath*:config/**/*.properties
  3. 通配符规则

    • *:匹配文件路径中的0个或多个字符,但不跨越目录。
    • **:匹配路径中的0个或多个目录。
    • ?:匹配文件路径中的一个字符。
  4. 多路径支持

    如果需要从多个位置加载属性文件,可以使用逗号(,)分隔各个路径,如:

    xml 复制代码
    <context:property-placeholder location="classpath:props/base.properties, file:/etc/app/config.override.properties"/>
  5. 变量使用

    可以在location属性中使用已经定义的系统属性或环境变量,使用${varName}语法,如:

    xml 复制代码
    <context:property-placeholder location="file:${user.home}/config/app.properties"/>
  6. 例子

    下面是一个实际例子,演示如何配置Spring来加载多个属性文件,包括类路径下和文件系统中的文件:

    xml 复制代码
    <context:property-placeholder location="classpath:config/app.properties, file:/path/to/external.properties"/>

    这个配置将会首先加载类路径下的app.properties,然后加载文件系统路径/path/to/下的external.properties

相关推荐
V+zmm1013416 分钟前
基于微信小程序的乡村政务服务系统springboot+论文源码调试讲解
java·微信小程序·小程序·毕业设计·ssm
Oneforlove_twoforjob41 分钟前
【Java基础面试题025】什么是Java的Integer缓存池?
java·开发语言·缓存
xmh-sxh-131443 分钟前
常用的缓存技术都有哪些
java
AiFlutter1 小时前
Flutter-底部分享弹窗(showModalBottomSheet)
java·前端·flutter
J不A秃V头A2 小时前
IntelliJ IDEA中设置激活的profile
java·intellij-idea
DARLING Zero two♡2 小时前
【优选算法】Pointer-Slice:双指针的算法切片(下)
java·数据结构·c++·算法·leetcode
小池先生2 小时前
springboot启动不了 因一个spring-boot-starter-web底下的tomcat-embed-core依赖丢失
java·spring boot·后端
CodeClimb2 小时前
【华为OD-E卷-木板 100分(python、java、c++、js、c)】
java·javascript·c++·python·华为od
程序员厉飞雨2 小时前
Android R8 耗时优化
android·java·前端
odng2 小时前
IDEA自己常用的几个快捷方式(自己的习惯)
java·ide·intellij-idea