@Value的用法

@Value属于spring的注解,在spring-beans包下,可以在 字段 或 方法参数 或 构造函数参数 上使用,通常用于属性注入。支持SpEL (Spring Expression Language)表达式来注入值,同时也支持属性占位符注入值。

篇幅较长,相对来说写的非常细了,基本上涉及到的面全有了,建议收藏慢慢看!

一、属性注入三种方式

使用@Value前提:

  1. 不能直接作用于静态变量(static);
  2. 不能直接作用于常量(final);
  3. 不能在非注册的类中使用(类需要被注册在spring上下文中,如用@Service,@RestController,@Component等);
  4. 使用这个类时,只能通过依赖注入的方式,用new的方式是不会自动注入这些配置的。

1.1.配置文件读取值

@Value(“${xxxx}”)注解从配置文件读取值的用法,也就是从application.yml / application.properties文件中获取值。

@Configuration
public class MyConfig {

    @Value("${spring.application.name}")
    private String name;

    public String getName() {
        return name;
    }
}

application.yml

spring:
  application:
    name: test

成功获取到application当中的值。

在这里插入图片描述

倘若application当中没有配置spring.application.name这时候启动项目就报异常了。

在这里插入图片描述

我们可以这样写:@Value("${spring.application.name:test111}") 代表的是假如application当中读不到值,那么就使用test111。这样可以完全避免没有设置值而启动报错的问题。当然也可以不设置默认值,比如@Value("${spring.application.name:}") 这样同样可以避免没有设置值启动报错的问题!

1.2.直接赋值

@Value("张三")属性注入有点类似于直接给属性赋值一样,但是实际开发当中这种应用场景非常少。

@Configuration
public class MyConfig {

    @Value("张三")
    private String name;

    public String getName() {
        return name;
    }
}

1.3.SpEL 表达式注入

@Value(“#{xxxx}”)是SpEL表达式的形式。想要深入了解SpEL表达式的可以看这一篇文章:https://blog.csdn.net/weixin_43888891/article/details/127520555

JAVA获得系统配置文件的System Properties,其中里面有一个属性就是user.language===zh,其实在spring当中我们可以通过SpEL 表达式来获取System Properties当中的属性值。

public class SystemProperties {
    public static void main(String[] args) {
        Properties properties = System.getProperties();
        Iterator<Map.Entry<Object, Object>> iterator = properties.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<Object, Object> entry = iterator.next();
            System.out.println(entry.getKey() + "===" + entry.getValue());
        }
    }
}

systemProperties是spring预定义的,我们可以拿来直接用的。

@Value("#{systemProperties['user.language']}")

二、property标签

@Value根本不是通过属性的set方法进行注入的,这个我也是亲自做了试验。@Value注解并不等于xml当中property标签,property标签是利用set方法来赋值的。并且property 当中的value属性也可以使用SpEL表达式。

<bean id="dog1" class="com.gzl.cn.springbootcache.config.Student">
     <property name="name" value="#{systemProperties['user.language']}"/>
     <property name="age" value="27"/>
 </bean>

三、构造函数注入

如果需要读取配置文件application.yml 的属性值,只需要在变量上加 @Value("${属性名}") 注解,就可以将配置文件 application.yml 的一个属性值赋值给变量。但是,如果我们在对象的构造方法中使用这个变量,结果发现这个变量的值为null。

@Configuration
public class MyConfig {

    @Value("${spring.application.name}")
    private String name;

    public MyConfig() {
        System.out.println(name);
    }
}

原因很简单构造器优先于属性注入,以至于属性还没注入进去,构造器当然拿不到值了。 那么在构造方法中如果要使用配置文件中的属性值,该怎么使用呢?见下方代码:

@Configuration
public class MyConfig {

    @Value("${spring.application.name}")
    private String name;

    public String getName() {
        return name;
    }

    public MyConfig(@Value("${spring.application.name}") String name1) {
        System.out.println(name1);
    }
}

四、方法注入

方法参数注入

@Configuration
public class MyConfig {

    @Bean
    public Student getName(@Value("${spring.application.name}")String name) {
        Student student = new Student();
        student.setName(name);
        return student;
    }
}

方法上注入,方法注入就是在方法上使用@Value,然后在注入到容器的过程当中他会读取@Value的值,然后将值传参访问这个方法。

@Configuration
public class MyConfig {

    private String name;

    @Value("${spring.application.name}")
    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

如果属性上使用了@Value然后set方法上也使用了@Value,那么这个属性最终会被赋值两次,保留下来的是set的值,因为set优先级比属性赋值要低。

五、静态变量注入

使用@Value注解是不允许在static变量注入的,包括get方法也是,直接会获取null值。原因很简单,@Value围绕的是注入到spring容器当中的这个单例对象,而static是类变量,所以肯定不可以的。可以理解为 类变量初始化优先于spring对象注入,所以他无法注入进去。

@Configuration
public class MyConfig {

    @Value("${spring.application.name}")
    private static String name;

    public static String getName() {
        return name;
    }
}

如果就想使用静态变量怎么办,其实是有很多种方案可以实现的。

5.1.通过方法注入

@Configuration
public class MyConfig {

    public static String name;

    @Value("${spring.application.name}")
    public void initName(String s) {
        name = s;
    }
}

5.2.通过@PostConstruct

Java中该注解的说明:@PostConstruct该注解被用来修饰一个非静态的void()方法。被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行,init()方法之前执行。

Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的方法)
@Configuration
public class MyConfig {

    public static String name;

    @Value("${spring.application.name}")
    private String s;

    @PostConstruct
    public void init(){
        name = s;
    }
}

5.3.继承InitializingBean接口

InitializingBean接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候会执行该方法。

@Configuration
public class MyConfig implements InitializingBean {

    public static String name;

    @Value("${spring.application.name}")
    private String s;

    @Override
    public void afterPropertiesSet() throws Exception {
        name = s;
    }
}

静态变量一般不建议设置为public,我们可以通过static 的 get方法来获取,因为静态变量设置为public,一旦有些地方没注意到把变量给改变值了,那这个值就彻底改变了,除非重启项目。

六、给不同类型变量注入

6.1.集合和数组

test:
  array1: aaa,bbb,ccc
  array2: 111,222,333

使用@Value("${ }")是直接属性赋值,@Value("#{}")是使用的SpEL表达式。SpEL表达式读是先读出来字符串,然后我们可以再进行处理。使用SpEL读不到的话是null,而使用属性赋值的话是空数组。

@Configuration
public class MyConfig {

    // 数组
    @Value("${test.array1:}")
    private String[] array1;

    // 集合
    @Value("${test.array1:}")
    private List<String> list1;

    // 集合
    @Value("#{'${test.array2}'.split(',')}")
    private List<String> list2;

    // 集合进一步做空数据处理,读不到值是一个null
    @Value("#{'${test.list:}'.empty ? null : '${test.list:}'.split(',')}")
    private List<String> testList;
}

6.2.map

test:
  map1: '{"name": "zhangsan", "sex": "male"}' 
  map2: '{"math": "90", "english": "85"}'
@Value("#{${test.map2}}")
private Map<String,String> map1;
@Value("#{${test.map2}}")
private Map<String,Integer> map2;

6.3.文件或url资源

@Value("classpath:com/gzl/spring/configinject/config.txt")
private Resource resourceFile; // 注入文件资源

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

七、大小写以及命名问题

不要在application.yml/properties文件中使用驼峰命名。尽量用-分割。
我看了一下原生框架的配置,发现人家确实没大小写。

file:
  winUploadPath: D:/opt/tongue/uploadPath

使用@Value("${file.win-upload-path}")照样可以读出winUploadPath的值。

@Configuration
public class MyConfig {

    @Value("${file.win-upload-path}")
    private String filePath;

    public String getFilePath() {
        return filePath;
    }
}

如果yml当中使用的win-upload-path,那么@value必须使用win-upload-path读,否则启动报错。

八、配合@PropertySource使用

springboot默认读取的都是application.yml,或者application.properties,但是有时候我们想把一些配置给独立起来,这时候可以采用@PropertySource。

新建properties,yml文件也是可以的,

在这里插入图片描述

demo.name=huang
demo.sex=1
demo.type=demo
@Component
@PropertySource(value = "demo.properties")
public class ReadByPropertySourceAndValue {

    @Value("${demo.name}")
    private String name;

    @Value("${demo.sex}")
    private int sex;

    @Value("${demo.type}")
    private String type;

    @Override
    public String toString() {
        return "ReadByPropertySourceAndValue{" +
                "name='" + name + '\'' +
                ", sex=" + sex +
                ", type='" + type + '\'' +
                '}';
    }
}

@PropertySource 和 @ConfigurationProperties配合使用

@Component
@PropertySource(value = "demo.properties")
@ConfigurationProperties(prefix = "demo")
public class ReadByPropertySourceAndValue {

    private String name;

    private int sex;

    private String type;

    @Override
    public String toString() {
        return "ReadByPropertySourceAndValue{" +
                "name='" + name + '\'' +
                ", sex=" + sex +
                ", type='" + type + '\'' +
                '}';
    }
}

九、@Value源码

代码当中并没有set方法,那他是如何赋值给属性值的呢?

@Configuration
public class MyConfig {
    @Value("${spring.application.name}")
    public String name;
}

@Value实际上是通过org.springframework.beans.factory.config.BeanPostProcessor来执行的。当然BeanPostProcessor是个接口,AutowiredAnnotationBeanPostProcessor是BeanPostProcessor的一个实现类,然后AutowiredAnnotationBeanPostProcessor负责检查是否有这个注解的存在。

在这里插入图片描述

AutowireCandidateResolver 的getSuggestedValue方法负责获取注解的value值。AutowireCandidateResolver实际上是个接口,真正的getSuggestedValue方法是访问的QualifierAnnotationAutowireCandidateResolver类当中的。

在这里插入图片描述

DefaultListableBeanFactory当中的resolveEmbeddedValue方法,通过表达式得到真正的值。

在这里插入图片描述

最终得到值通过反射Field的set赋值

在这里插入图片描述

官网源码:https://github.com/spring-projects/spring-framework/blob/main/spring-beans/src/main/java/org/springframework/beans/factory/annotation/Value.java

写作不易,如果这篇文章有帮助到您,麻烦您给小编留个赞哈!

  • 17
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Java中,我们可以使用JSON库来解析和处理JSON数据。要根据某一字段对JSON数据进行删除,可以按照以下步骤: 1. 首先,使用JSON库将JSON数据解析成Java对象。常用的JSON库有Jackson、Gson等,你可以根据自己的需要选择。 2. 接下来,遍历解析后的Java对象,找到符合条件的数据项。这可以通过使用条件语句和循环来完成。判断某一字段的值是否符合条件,如果符合则进行删除操作。 3. 在找到需要删除的数据项后,可以使用JSON库提供的删除方法来实现删除操作。具体的删除方式取决于所使用的JSON库。例如,如果使用的是Jackson库,可以使用ObjectMapper的remove方法来删除指定字段。 4. 最后,将删除后的Java对象序列化为JSON字符串,以便进一步处理或输出。同样,根据所使用的JSON库,可以调用相应的方法将Java对象转换为JSON字符串。 下面是一个简单的示例代码,演示了根据某一字段对JSON数据进行删除的过程: ```java import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; public class JsonDeleteExample { public static void main(String[] args) throws Exception { String jsonData = "{\"employees\":[{\"name\":\"John\",\"age\":30},{\"name\":\"Jane\",\"age\":25}]}"; String fieldName = "name"; String fieldValue = "John"; // 解析JSON数据 ObjectMapper objectMapper = new ObjectMapper(); JsonNode jsonNode = objectMapper.readTree(jsonData); // 遍历解析后的Java对象 ArrayNode employeesNode = (ArrayNode) jsonNode.get("employees"); for (int i = 0; i < employeesNode.size(); i++) { JsonNode employeeNode = employeesNode.get(i); // 判断字段的值是否符合条件 if (employeeNode.get(fieldName).asText().equals(fieldValue)) { // 删除该节点 employeesNode.remove(i); i--; // 因为数组大小变小,需要调整索引 } } // 序列化为JSON字符串 String updatedJsonData = objectMapper.writeValueAsString(jsonNode); System.out.println(updatedJsonData); } } ``` 以上代码假设JSON数据为`{"employees":[{"name":"John","age":30},{"name":"Jane","age":25}]}`,要删除`name`字段值为`John`的数据项。运行该代码,输出结果为`{"employees":[{"name":"Jane","age":25}]}`,已成功删除指定字段的数据项。 请根据自己的实际需求调整代码中的字段名称和数值,以适应不同的JSON数据和删除条件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

怪 咖@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值