评论

收藏

[Java] 详解SpringBoot注入数据的方式

编程语言 编程语言 发布于:2021-10-06 14:12 | 阅读数:211 | 评论:0

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

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]}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持CodeAE代码之家
原文链接:https://segmentfault.com/a/1190000017485165

关注下面的标签,发现更多相似文章