Spring:向静态访问类注入一个值



考虑以下类:

public class ExpressionTokenClassifier {
private static final String       PROMQL_KEYWORDS = "promql-keywords.json";
private static final List<String> KEYWORDS;
static {
List<PromQLKeyword> words = KeywordsExtractor.extractKeywords(PROMQL_KEYWORDS);
KEYWORDS = words.stream().map(PromQLKeyword::getName).collect(Collectors.toList());
}
public static void classifyTokens(List<ExpressionToken> tokens) {
... // KEYWORDS is used in here
}
}

注意在静态初始化块中指定和使用的硬连线文件名(PROMQL_KEYWORDS)。这是有效的,但我想删除硬编码的值,而不是使用依赖注入(Spring)从application.yaml设置值。这个类只能静态使用。

我的研究表明,Spring框架不允许使用@Value注释设置静态字段。我已经看到了一些变通的建议,但不明白他们是如何工作的。下面是我尝试这样做的一个示例:

@Component
public class ExpressionTokenClassifier2 {
private static final List<String> KEYWORDS;
private static String             KEYWORDS_FILE;
@Value("${app.keywords-file}")
public void setKeywordsFileName(String name) {
KEYWORDS_FILE = name;
}
static {
List<PromQLKeyword> words = KeywordsExtractor.extractKeywords(KEYWORDS_FILE);
KEYWORDS = words.stream().map(PromQLKeyword::getName).collect(Collectors.toList());
}
public static void classifyTokens(List<ExpressionToken> tokens) {
... // KEYWORDS is used in here
}
}

当我尝试它时,由于NPE (KEYWORDS_FILE为空),应用程序无法启动。我的直接问题是:何时何地调用setKeywordsFileName()方法?没有,据我所知,结果是一致的。我是不是漏掉了什么逻辑?

有谁知道实现这个的方法吗?我可以改变这个类让它被实例化而不是静态访问,但是使用这个类的类是也是静态访问的类。我真的不想修改一堆代码来解决这个问题。

:

经过进一步调查,似乎这在本质上是不可行的,至少在没有大量额外工作的情况下是不可行的,而这可能会破坏目的。对我来说,这个链接很好地描述了情况。

如何从应用程序中赋值。属性到静态变量?

看来我得考虑一段时间了。

我将只使用@Component@PostConstruct方法的init任务:

Spring组件是单例的,所以不需要static。

@Component // singleton
public class ExpressionTokenClassifier {

@Value("${app.keywords-file}")
private String file;
private List<String> KEYWORDS;
@PostConstruct
public void init() {
[...]
}
}

如果静态访问是必要的,您可以在应用程序启动后立即初始化您的静态类:

public class ExpressionTokenClassifier {

private List<String> KEYWORDS;
static void init(String file) {
List<PromQLKeyword> words = KeywordsExtractor.extractKeywords(file);
KEYWORDS = words.stream().map(PromQLKeyword::getName).collect(Collectors.toList());
}

public static void classifyTokens(List<ExpressionToken> tokens) {
// KEYWORDS is used in here
}
}
@Component
public class ExpressionTokenClassifierInitializer {

@Value("${app.keywords-file}")
private String file;
@EventListener(ContextRefreshedEvent.class)
public void onApplicationStartedEvent() {
ExpressionTokenClassifier.init(file);
}
}

相关内容

  • 没有找到相关文章

最新更新