详解SpringBoot注入数据的方式

小编 2026-07-04 阅读:1218 评论:0
关于注入数据说明 1.不通过配置文件注入数据 通过@Value将外部的值动态注入到Bean中,使用的情况有: 注入普通字符串 注入操作系统属性 注入表达式结果 注入其他Bean...

关于注入数据说明

\"\"

1.不通过配置文件注入数据

通过@Value将外部的值动态注入到Bean中,使用的情况有:

  • 注入普通字符串
  • 注入操作系统属性
  • 注入表达式结果
  • 注入其他Bean属性:注入Student对象的属性name
  • 注入文件资源
  • 注入URL资源

辅助代码

package com.hannpang.model;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component(value = \"st\")//对student进行实例化操作
public class Student {
  @Value(\"悟空\")
  private String name;

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }
}

测试@Value的代码

package com.hannpang.model;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

@Component
public class SimpleObject {

  @Value(\"注入普通字符串\")
  private String normal;

  //关于属性的KEY可以查看System类说明
  @Value(\"#{systemProperties[\'java.version\']}\")//-->使用了SpEL表达式
  private String systemPropertiesName; // 注入操作系统属性

  @Value(\"#{T(java.lang.Math).random()*80}\")//获取随机数
  private double randomNumber; //注入表达式结果

  @Value(\"#{1+2}\")
  private double sum; //注入表达式结果 1+2的求和

  @Value(\"classpath:os.yaml\")
  private Resource resourceFile; // 注入文件资源

  @Value(\"http://www.baidu.com\")
  private Resource testUrl; // 注入URL资源

  @Value(\"#{st.name}\")
  private String studentName;

  //省略getter和setter方法

  @Override
  public String toString() {
    return \"SimpleObject{\" +
        \"normal=\'\" + normal + \'\\\'\' +
        \", systemPropertiesName=\'\" + systemPropertiesName + \'\\\'\' +
        \", randomNumber=\" + randomNumber +
        \", sum=\" + sum +
        \", resourceFile=\" + resourceFile +
        \", testUrl=\" + testUrl +
        \", studentName=\'\" + studentName + \'\\\'\' +
        \'}\';
  }
}

Spring的测试代码

package com.hannpang;

import com.hannpang.model.SimpleObject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class Demo04BootApplicationTests {

  @Autowired
  private SimpleObject so;

  @Test
  public void contextLoads() {
    System.out.println(so);
  }
}

运行结果为:SimpleObject{normal=\'注入普通字符串\', systemPropertiesName=\'1.8.0_172\', randomNumber=56.631954541947266, sum=3.0, resourceFile=class path resource [os.yaml], testUrl=URL [http://www.baidu.com], studentName=\'悟空\'}

2.通过配置文件注入数据

通过@Value将外部配置文件的值动态注入到Bean中。配置文件主要有两类:

  • application.properties、application.yaml application.properties在spring boot启动时默认加载此文件
  • 自定义属性文件。自定义属性文件通过@PropertySource加载。@PropertySource可以同时加载多个文件,也可以加载单个文件。如果相同第一个属性文件和第二属性文件存在相同key,则最后一个属性文件里的key启作用。加载文件的路径也可以配置变量,如下文的${anotherfile.configinject},此值定义在第一个属性文件config.properties

在application.properties中加入如下测试代码

app.name=一步教育

在resources下面新建第一个属性文件config.properties内容如下

book.name=西游记
anotherfile.configinject=system

在resources下面新建第二个属性文件config_system.properties内容如下

我的目的是想system的值使用第一个属性文件中定义的值
book.name.author=吴承恩

下面通过@Value(“${app.name}”)语法将属性文件的值注入bean属性值,详细代码见:

package com.hannpang.test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

@Component
@PropertySource(value = {\"classpath:config.properties\",\"classpath:config_${anotherfile.configinject}.properties\"})
public class LoadPropsTest {

  @Value(\"${app.name}\")
  private String appName; // 这里的值来自application.properties,spring boot启动时默认加载此文件

  @Value(\"${book.name}\")
  private String bookName; // 注入第一个配置外部文件属性

  @Value(\"${book.name.author}\")
  private String author; // 注入第二个配置外部文件属性

  @Autowired
  private Environment env; // 注入环境变量对象,存储注入的属性值

  //省略getter和setter方法


  public void setAuthor(String author) {
    this.author = author;
  }


  @Override
  public String toString(){
    StringBuilder sb = new StringBuilder();
    sb.append(\"bookName=\").append(bookName).append(\"\\r\\n\")
        .append(\"author=\").append(author).append(\"\\r\\n\")
        .append(\"appName=\").append(appName).append(\"\\r\\n\")
        .append(\"env=\").append(env).append(\"\\r\\n\")
        // 从eniroment中获取属性值
        .append(\"env=\").append(env.getProperty(\"book.name.author\")).append(\"\\r\\n\");
    return sb.toString();
  }

}

测试代码

package com.hannpang;

import com.hannpang.model.SimpleObject;
import com.hannpang.test.LoadPropsTest;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class Demo04BootApplicationTests {

  @Autowired
  private LoadPropsTest lpt;

  @Test
  public void loadPropertiesTest() {

    System.out.println(lpt);
  }
}

运行结果为:
bookName=西游记
author=吴承恩
appName=一步教育
env=StandardEnvironment {activeProfiles=[], defaultProfiles=[default], propertySources=[ConfigurationPropertySourcesPropertySource {name=\'configurationProperties\'}, MapPropertySource {name=\'Inlined Test Properties\'}, MapPropertySource {name=\'systemProperties\'}, OriginAwareSystemEnvironmentPropertySource {name=\'systemEnvironment\'}, RandomValuePropertySource {name=\'random\'}, OriginTrackedMapPropertySource {name=\'applicationConfig: [classpath:/application.properties]\'}, ResourcePropertySource {name=\'class path resource [config_system.properties]\'}, ResourcePropertySource {name=\'class path resource [config.properties]\'}]}
env=吴承恩

3. #{...}和${...}的区别演示

A .${…}的用法

{}里面的内容必须符合SpEL表达式,通过@Value(“${app.name}”)可以获取属性文件中对应的值,但是如果属性文件中没有这个属性,则会报错。可以通过赋予默认值解决这个问题,如@Value(\"${app.name:胖先森}\")

部分代码

// 如果属性文件没有app.name,则会报错
// @Value(\"${app.name}\")
// private String name;

// 使用app.name设置值,如果不存在则使用默认值
@Value(\"${app.name:胖先森}\")
private String name;

B.#{...}的用法

部分代码直接演示

// SpEL:调用字符串Hello World的concat方法
@Value(\"#{\'Hello World\'.concat(\'!\')}\")
private String helloWorld;

// SpEL: 调用字符串的getBytes方法,然后调用length属性
@Value(\"#{\'Hello World\'.bytes.length}\")
private String helloWorldbytes;

C.#{...}${...}混合使用

${...}和#{...}可以混合使用,如下文代码执行顺序:通过${server.name}从属性文件中获取值并进行替换,然后就变成了 执行SpEL表达式{‘server1,server2,server3\'.split(‘,\')}。

// SpEL: 传入一个字符串,根据\",\"切分后插入列表中, #{}和${}配置使用(注意单引号,注意不能反过来${}在外面,#{}在里面)
@Value(\"#{\'${server.name}\'.split(\',\')}\")
private List<String> servers;

在上文中在#{}外面,${}在里面可以执行成功,那么反过来是否可以呢${}在外面,#{}在里面,如代码

// SpEL: 注意不能反过来${}在外面,#{}在里面,这个会执行失败
@Value(\"${#{\'HelloWorld\'.concat(\'_\')}}\")
private List<String> servers2;

答案是不能。
因为spring执行${}是时机要早于#{}。
在本例中,Spring会尝试从属性中查找#{‘HelloWorld\'.concat(‘_\')},那么肯定找到,由上文已知如果找不到,然后报错。所以${}在外面,#{}在里面是非法操作

D.用法总结

  • #{…} 用于执行SpEl表达式,并将内容赋值给属性
  • ${…} 主要用于加载外部属性文件中的值
  • #{…} 和${…} 可以混合使用,但是必须#{}外面,${}在里面

4.@Value获取值和@ConfigurationProperties获取值比较

@ConfigurationProperties @Value
功能 批量注入配置文件中的属性 一个个指定
松散绑定(松散语法) 支持 不支持
SpEL 不支持 支持
JSR303数据校验 支持 不支持
复杂类型封装 支持 不支持

配置文件yml还是properties他们都能获取到值;

  • 如果说,我们只是在某个业务逻辑中需要获取一下配置文件中的某项值,使用@Value;
  • 如果说,我们专门编写了一个javaBean来和配置文件进行映射,我们就直接使用@ConfigurationProperties;

关于数据校验的部分代码

@Component
@ConfigurationProperties(prefix = \"person\")
@Validated
public class Person {
  //lastName必须是邮箱格式
  @Email
  private String lastName;

5. @ImportResource引入配置文件

不推荐的使用方式

Spring Boot里面没有Spring的配置文件,我们自己编写的配置文件,也不能自动识别;

想让Spring的配置文件生效,加载进来;@ImportResource标注在一个配置类上

@ImportResource(locations = {\"classpath:beans.xml\"})
导入Spring的配置文件让其生效

编写配置文件信息

<?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=\"helloService\" class=\"com.hanpang.springboot.service.HelloService\"></bean>
</beans>
大概了解就好,我们基本上不使用这种方式

6.@Configuration注解

SpringBoot推荐给容器中添加组件的方式;推荐使用全注解的方式

1、配置类@Configuration作用于类上,相当于一个xml配置文件

2、使用@Bean给容器中添加组件,作用于方法上

/**
 * @Configuration:指明当前类是一个配置类;就是来替代之前的Spring配置文件
 *
 * 在配置文件中用<bean><bean/>标签添加组件
 * <bean id=\"helloService\" class=\"com.hanpang.springboot.service.HelloService\"></bean>
 */
@Configuration
public class MyAppConfig {

  //将方法的返回值添加到容器中;容器中这个组件默认的id就是方法名
  @Bean
  public HelloService helloService02(){
    System.out.println(\"配置类@Bean给容器中添加组件了...\");
    return new HelloService();
  }
}

使用Bean注入太麻烦,我们更加喜欢使用扫描的方式

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
 
import com.wx.dao.IUserDao;
import com.wx.dao.UserDaoImpl;
 
//通过该注解来表明该类是一个Spring的配置,相当于一个传统的ApplicationContext.xml
@Configuration
//相当于配置文件里面的<context:component-scan/>标签,扫描这些包下面的类的注解
@ComponentScan(basePackages=\"com.hanpang.dao,com.hanpang.service\")
public class SpringConfig {
  // 通过该注解来表明是一个Bean对象,相当于xml中的<bean>
  //bean的id值默认是方法名userDao
  /*
  @Bean
  public HelloService helloService02(){
    System.out.println(\"配置类@Bean给容器中添加组件了...\");
    return new HelloService();
  }
  */
}

附录

随机数

${random.value}、${random.int}、${random.long}
${random.int(10)}、${random.int[1024,65536]}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

版权声明

本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。

热门文章
  • Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering

    Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering
    Problem Statement 我们考虑一个具有马尔可夫性质、非线性、非高斯的状态空间模型(State Space Model):对于一个时间序列上的观测结果{yt,t∈N}\\{ y_t , t \\in N \\}{yt​,t∈N},我们认为每个观测结果yty_tyt​的生成依赖于一个无法直接观察的隐变量xt∈{xt,t∈N}x_t \\in \\{x_t , t \\in N \\}xt​∈{xt​,t∈N},即:p(...
  • 机房智能化温湿度解决方式之POE供电以太网温湿度传感器

    机房智能化温湿度解决方式之POE供电以太网温湿度传感器
    机房智能化温湿度解决方式之POE供电以太网温湿度传感器 北京盈创力和电子科技有限公司 智能型TCP网口温湿度记录仪 北京IP网络温湿度记录仪厂家,北京盈创力和 北京智能型TCP网口温湿度记录仪IP网络温湿度记录仪是一种新型的基于TCP/IP协议双绞线以太网标准温湿度采集模块,利用它可以实现现场温度值、相对湿度值的采集,同时利用其自身的RJ45通信接口可以方便地和机房监控主机或交换机集线器进行联网。 工作于-40℃~85℃工业级带...
  • Hive 系统函数及示例

    Hive 系统函数及示例
    查看所有系统函数 show functions; 函数分类 内置函数【系统函数】 数学函数: floor、round、ceil、cos、log2等 字符串函数: length、reverse、trim、lower、get_json_object、repeat等 收集函数: size 转换函数: cast 日期函数: year、month、datediff、date、date_add等 条件函数: coalesce、case…w...
  • HTTP状态保持的原理

    HTTP状态保持的原理
    a)在用户登录之后,浏览器返回响应的时候会在响应中添加上cookieb)浏览器接收到cookie之后会自动保存c)当用户再次请求同一服务器中的其他网页的时候,浏览器会自动带上之前保存的cookied)服务接收到请求之后可以请 request 对象中取到cookie 判断当前用户是否登录  Http是无状态的,就是连接时数据互通,关闭后...
  • CSRF的原理和防范措施

    CSRF的原理和防范措施
    a)攻击原理:i.用户C访问正常网站A时进行登录,浏览器保存A的cookieii.用户C再访问攻击网站B,网站B上有某个隐藏的链接或者图片标签会自动请求网站A的URL地址,例如表单提交,传指定的参数iii.而攻击网站B在访问网站A的时候,浏览器会自动带上网站A的cookieiv.所以网站A在接收到请求之后可判断当前用户是登录状态,所以...
标签列表