热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

详解SpringBoot注入数据的方式

这篇文章主要介绍了详解SpringBoot注入数据的方式,详细的介绍了几种注入方式,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

关于注入数据说明

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 servers;

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

// SpEL: 注意不能反过来${}在外面,#{}在里面,这个会执行失败
@Value("${#{'HelloWorld'.concat('_')}}")
private List 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的配置文件让其生效

编写配置文件信息

<&#63;xml version="1.0" encoding="UTF-8"&#63;>

  
大概了解就好,我们基本上不使用这种方式

6.@Configuration注解

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

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

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

/**
 * @Configuration:指明当前类是一个配置类;就是来替代之前的Spring配置文件
 *
 * 在配置文件中用标签添加组件
 * 
 */
@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
//相当于配置文件里面的标签,扫描这些包下面的类的注解
@ComponentScan(basePackages="com.hanpang.dao,com.hanpang.service")
public class SpringConfig {
  // 通过该注解来表明是一个Bean对象,相当于xml中的
  //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]}

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


推荐阅读
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • r2dbc配置多数据源
    R2dbc配置多数据源问题根据官网配置r2dbc连接mysql多数据源所遇到的问题pom配置可以参考官网,不过我这样配置会报错我并没有这样配置将以下内容添加到pom.xml文件d ... [详细]
  • docker增加restart=always, docker重启后自动启动容器的方法
    本文介绍了在运行docker容器时如何添加参数来保证每次docker服务重启后容器也自动重启的方法,以及如何使用命令来更新已启动的容器。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 处理docker容器时间和宿主机时间不一致问题的方法
    本文介绍了处理docker容器时间和宿主机时间不一致问题的方法,包括复制主机的localtime到容器、处理报错情况以及重启容器的步骤。通过这些方法,可以解决docker容器时间和宿主机时间不一致的问题。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • Tomcat/Jetty为何选择扩展线程池而不是使用JDK原生线程池?
    本文探讨了Tomcat和Jetty选择扩展线程池而不是使用JDK原生线程池的原因。通过比较IO密集型任务和CPU密集型任务的特点,解释了为何Tomcat和Jetty需要扩展线程池来提高并发度和任务处理速度。同时,介绍了JDK原生线程池的工作流程。 ... [详细]
  • 本文介绍了Java的集合及其实现类,包括数据结构、抽象类和具体实现类的关系,详细介绍了List接口及其实现类ArrayList的基本操作和特点。文章通过提供相关参考文档和链接,帮助读者更好地理解和使用Java的集合类。 ... [详细]
  • 本文介绍了电流源并联合并的方法,以及谐振电路的原理。谐振电路具有很强的选频能力,通过将电感和电容连接在一起,电流和电压会产生震荡。谐振频率的大小取决于电感和电容的大小,而电路中的电阻会逐渐降低震荡的幅度。电阻和电容组成的电路中,当电容放完电后,电阻两端的电压为0,电流不再流过电容。然而,电感是一种特殊的器件,当有电流流过时,线圈会产生感应磁场,阻止电流的流动,从而使电流不会减小。 ... [详细]
  • 标题: ... [详细]
  • 本文讨论了如何在codeigniter中识别来自angularjs的请求,并提供了两种方法的代码示例。作者尝试了$this->input->is_ajax_request()和自定义函数is_ajax(),但都没有成功。最后,作者展示了一个ajax请求的示例代码。 ... [详细]
  • 突破MIUI14限制,自定义胶囊图标、大图标样式,支持任意APP
    本文介绍了如何突破MIUI14的限制,实现自定义胶囊图标和大图标样式,并支持任意APP。需要一定的动手能力和主题设计师账号权限或者会主题pojie。详细步骤包括应用包名获取、素材制作和封包获取等。 ... [详细]
  • iOS超签签名服务器搭建及其优劣势
    本文介绍了搭建iOS超签签名服务器的原因和优势,包括不掉签、用户可以直接安装不需要信任、体验好等。同时也提到了超签的劣势,即一个证书只能安装100个,成本较高。文章还详细介绍了超签的实现原理,包括用户请求服务器安装mobileconfig文件、服务器调用苹果接口添加udid等步骤。最后,还提到了生成mobileconfig文件和导出AppleWorldwideDeveloperRelationsCertificationAuthority证书的方法。 ... [详细]
  • 本文讨论了如何使用Web.Config进行自定义配置节的配置转换。作者提到,他将msbuild设置为详细模式,但转换却忽略了带有替换转换的自定义部分的存在。 ... [详细]
author-avatar
迷失港湾的豪
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有