经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring Boot » 查看文章
详解SpringBoot注入数据的方式
来源:jb51  时间:2018/12/24 10:44:04  对本文有异议

关于注入数据说明

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

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

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

辅助代码

  1. package com.hannpang.model;
  2.  
  3. import org.springframework.beans.factory.annotation.Value;
  4. import org.springframework.stereotype.Component;
  5.  
  6. @Component(value = "st")//对student进行实例化操作
  7. public class Student {
  8. @Value("悟空")
  9. private String name;
  10.  
  11. public String getName() {
  12. return name;
  13. }
  14.  
  15. public void setName(String name) {
  16. this.name = name;
  17. }
  18. }

测试@Value的代码

  1. package com.hannpang.model;
  2.  
  3. import org.springframework.beans.factory.annotation.Value;
  4. import org.springframework.core.io.Resource;
  5. import org.springframework.stereotype.Component;
  6.  
  7. @Component
  8. public class SimpleObject {
  9.  
  10. @Value("注入普通字符串")
  11. private String normal;
  12.  
  13. //关于属性的KEY可以查看System类说明
  14. @Value("#{systemProperties['java.version']}")//-->使用了SpEL表达式
  15. private String systemPropertiesName; // 注入操作系统属性
  16.  
  17. @Value("#{T(java.lang.Math).random()*80}")//获取随机数
  18. private double randomNumber; //注入表达式结果
  19.  
  20. @Value("#{1+2}")
  21. private double sum; //注入表达式结果 1+2的求和
  22.  
  23. @Value("classpath:os.yaml")
  24. private Resource resourceFile; // 注入文件资源
  25.  
  26. @Value("http://www.baidu.com")
  27. private Resource testUrl; // 注入URL资源
  28.  
  29. @Value("#{st.name}")
  30. private String studentName;
  31.  
  32. //省略getter和setter方法
  33.  
  34. @Override
  35. public String toString() {
  36. return "SimpleObject{" +
  37. "normal='" + normal + '\'' +
  38. ", systemPropertiesName='" + systemPropertiesName + '\'' +
  39. ", randomNumber=" + randomNumber +
  40. ", sum=" + sum +
  41. ", resourceFile=" + resourceFile +
  42. ", testUrl=" + testUrl +
  43. ", studentName='" + studentName + '\'' +
  44. '}';
  45. }
  46. }

Spring的测试代码

  1. package com.hannpang;
  2.  
  3. import com.hannpang.model.SimpleObject;
  4. import org.junit.Test;
  5. import org.junit.runner.RunWith;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.boot.test.context.SpringBootTest;
  8. import org.springframework.test.context.junit4.SpringRunner;
  9.  
  10. @RunWith(SpringRunner.class)
  11. @SpringBootTest
  12. public class Demo04BootApplicationTests {
  13.  
  14. @Autowired
  15. private SimpleObject so;
  16.  
  17. @Test
  18. public void contextLoads() {
  19. System.out.println(so);
  20. }
  21. }

运行结果为: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中加入如下测试代码

  1. app.name=一步教育

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

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

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

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

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

  1. package com.hannpang.test;
  2.  
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.beans.factory.annotation.Value;
  5. import org.springframework.context.annotation.PropertySource;
  6. import org.springframework.core.env.Environment;
  7. import org.springframework.stereotype.Component;
  8.  
  9. @Component
  10. @PropertySource(value = {"classpath:config.properties","classpath:config_${anotherfile.configinject}.properties"})
  11. public class LoadPropsTest {
  12.  
  13. @Value("${app.name}")
  14. private String appName; // 这里的值来自application.properties,spring boot启动时默认加载此文件
  15.  
  16. @Value("${book.name}")
  17. private String bookName; // 注入第一个配置外部文件属性
  18.  
  19. @Value("${book.name.author}")
  20. private String author; // 注入第二个配置外部文件属性
  21.  
  22. @Autowired
  23. private Environment env; // 注入环境变量对象,存储注入的属性值
  24.  
  25. //省略getter和setter方法
  26.  
  27.  
  28. public void setAuthor(String author) {
  29. this.author = author;
  30. }
  31.  
  32.  
  33. @Override
  34. public String toString(){
  35. StringBuilder sb = new StringBuilder();
  36. sb.append("bookName=").append(bookName).append("\r\n")
  37. .append("author=").append(author).append("\r\n")
  38. .append("appName=").append(appName).append("\r\n")
  39. .append("env=").append(env).append("\r\n")
  40. // 从eniroment中获取属性值
  41. .append("env=").append(env.getProperty("book.name.author")).append("\r\n");
  42. return sb.toString();
  43. }
  44.  
  45. }

测试代码

  1. package com.hannpang;
  2.  
  3. import com.hannpang.model.SimpleObject;
  4. import com.hannpang.test.LoadPropsTest;
  5. import org.junit.Test;
  6. import org.junit.runner.RunWith;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.boot.test.context.SpringBootTest;
  9. import org.springframework.test.context.junit4.SpringRunner;
  10.  
  11. @RunWith(SpringRunner.class)
  12. @SpringBootTest
  13. public class Demo04BootApplicationTests {
  14.  
  15. @Autowired
  16. private LoadPropsTest lpt;
  17.  
  18. @Test
  19. public void loadPropertiesTest() {
  20.  
  21. System.out.println(lpt);
  22. }
  23. }

运行结果为:
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:胖先森}")

部分代码

  1. // 如果属性文件没有app.name,则会报错
  2. // @Value("${app.name}")
  3. // private String name;
  4.  
  5. // 使用app.name设置值,如果不存在则使用默认值
  6. @Value("${app.name:胖先森}")
  7. private String name;

B.#{...}的用法

部分代码直接演示

  1. // SpEL:调用字符串Hello World的concat方法
  2. @Value("#{'Hello World'.concat('!')}")
  3. private String helloWorld;
  4.  
  5. // SpEL: 调用字符串的getBytes方法,然后调用length属性
  6. @Value("#{'Hello World'.bytes.length}")
  7. private String helloWorldbytes;

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

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

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

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

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

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

D.用法总结

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

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

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

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

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

关于数据校验的部分代码

  1. @Component
  2. @ConfigurationProperties(prefix = "person")
  3. @Validated
  4. public class Person {
  5. //lastName必须是邮箱格式
  6. @Email
  7. private String lastName;

5. @ImportResource引入配置文件

不推荐的使用方式

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

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

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

编写配置文件信息

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <bean id="helloService" class="com.hanpang.springboot.service.HelloService"></bean>
  6. </beans>
大概了解就好,我们基本上不使用这种方式

6.@Configuration注解

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

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

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

  1. /**
  2. * @Configuration:指明当前类是一个配置类;就是来替代之前的Spring配置文件
  3. *
  4. * 在配置文件中用<bean><bean/>标签添加组件
  5. * <bean id="helloService" class="com.hanpang.springboot.service.HelloService"></bean>
  6. */
  7. @Configuration
  8. public class MyAppConfig {
  9.  
  10. //将方法的返回值添加到容器中;容器中这个组件默认的id就是方法名
  11. @Bean
  12. public HelloService helloService02(){
  13. System.out.println("配置类@Bean给容器中添加组件了...");
  14. return new HelloService();
  15. }
  16. }

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

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

附录

随机数

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

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

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号