You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring中如何在@Value注解中动态注入拼接后的配置值?

解决Spring中动态根据ID注入配置属性的问题

问题场景

现有application.properties配置了多组图书属性:

book.name1 = War and Piece
book.author1 = Leo Tolstoy
book.name2 = Crime and Punishment
book.author2 = Dostoevsky 
book.name3 = To Kill a Mockingbird
book.author3 = Harper Lee

原代码尝试通过Book类的静态bookid自增,在@Value注解中拼接ID动态获取配置,但调用后输出未解析的表达式${book.name.concat(bookid)} by ${book.author.concat(bookid)},无法达到预期效果。

问题根源

  1. 时机不匹配:Spring的@Value注解在Bean定义解析阶段就会处理表达式,而bookid是在Book构造函数执行时才自增,此时表达式已经完成解析,无法动态更新。
  2. 语法错误:@Value不支持直接用concat(bookid)这种自定义拼接逻辑,即使使用SpEL表达式引用静态变量,也只能获取解析时的初始值,后续自增不会生效。
  3. 线程安全隐患:静态bookid在多线程创建Book实例时会出现值混乱的问题。

正确实现方案

方案一:用@ConfigurationProperties批量绑定配置

这是最简洁的批量读取同前缀配置的方式,支持列表或Map格式。

1. 定义配置接收类
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Map;

@Component
@ConfigurationProperties(prefix = "book")
public class BookProperties {
    // 用Map接收原格式的配置,key为数字字符串(如"1"、"2")
    private Map<String, String> name;
    private Map<String, String> author;

    // Getter & Setter
    public Map<String, String> getName() { return name; }
    public void setName(Map<String, String> name) { this.name = name; }
    public Map<String, String> getAuthor() { return author; }
    public void setAuthor(Map<String, String> author) { this.author = author; }
}
2. 配置类创建Book实例列表
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;

@Configuration
public class LibraryConfig {
    private final BookProperties bookProperties;

    public LibraryConfig(BookProperties bookProperties) {
        this.bookProperties = bookProperties;
    }

    @Bean
    public List<Book> books() {
        List<Book> bookList = new ArrayList<>();
        int bookCount = bookProperties.getName().size();
        
        for (int i = 1; i <= bookCount; i++) {
            String id = String.valueOf(i);
            Book book = new Book();
            book.setName(bookProperties.getName().get(id));
            book.setAuthor(bookProperties.getAuthor().get(id));
            bookList.add(book);
        }
        return bookList;
    }

    @Bean
    public UniversityLibrary universityLibrary(List<Book> books) {
        return new UniversityLibrary(books);
    }
}
3. 简化Book类

去掉静态变量和@Value,仅保留属性和基础方法:

public class Book {
    private String name;
    private String author;

    // Getter & Setter
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public String getAuthor() { return author; }
    public void setAuthor(String author) { this.author = author; }

    public String getBook() {
        return name + " by " + author;
    }
}

方案二:通过Environment动态获取配置

直接利用Spring的Environment对象,根据传入的ID读取对应配置。

1. 修改Book类

通过构造函数注入Environment和ID,动态读取配置:

import org.springframework.core.env.Environment;

public class Book {
    private String name;
    private String author;

    public Book(Environment environment, int bookId) {
        this.name = environment.getProperty("book.name" + bookId);
        this.author = environment.getProperty("book.author" + bookId);
    }

    public String getBook() {
        return name + " by " + author;
    }
}
2. 配置类创建实例
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import java.util.ArrayList;
import java.util.List;

@Configuration
public class LibraryConfig {
    private final Environment environment;

    public LibraryConfig(Environment environment) {
        this.environment = environment;
    }

    @Bean
    public List<Book> books() {
        List<Book> bookList = new ArrayList<>();
        // 可通过配置项指定图书数量,更灵活
        int bookCount = Integer.parseInt(environment.getProperty("book.count", "3"));
        
        for (int i = 1; i <= bookCount; i++) {
            bookList.add(new Book(environment, i));
        }
        return bookList;
    }

    @Bean
    public UniversityLibrary universityLibrary(List<Book> books) {
        return new UniversityLibrary(books);
    }
}

此时可在application.properties中添加book.count=3来指定图书数量。


方案三:手动构造Book实例

如果不需要Spring管理属性注入,可直接在配置类中读取配置创建实例:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import java.util.ArrayList;
import java.util.List;

@Configuration
public class LibraryConfig {
    private final Environment environment;

    public LibraryConfig(Environment environment) {
        this.environment = environment;
    }

    @Bean
    public List<Book> books() {
        List<Book> bookList = new ArrayList<>();
        
        Book book1 = new Book();
        book1.setName(environment.getProperty("book.name1"));
        book1.setAuthor(environment.getProperty("book.author1"));
        bookList.add(book1);

        Book book2 = new Book();
        book2.setName(environment.getProperty("book.name2"));
        book2.setAuthor(environment.getProperty("book.author2"));
        bookList.add(book2);

        Book book3 = new Book();
        book3.setName(environment.getProperty("book.name3"));
        book3.setAuthor(environment.getProperty("book.author3"));
        bookList.add(book3);

        return bookList;
    }

    @Bean
    public UniversityLibrary universityLibrary(List<Book> books) {
        return new UniversityLibrary(books);
    }
}

Book类保持方案一中的简化版本即可。

内容的提问来源于stack exchange,提问作者Korol_ER

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 13:34:58