上下文:
我处理带有@Scheduled
批注的报表,并且当从Component
属性调用Service
的属性@Value
初始化时,即使它实际上存在于.properties
中,也无法打印该报表在@PostConstruct
中。
说明:
ReportProcessor
界面和InventoryReportProcessor
实现:
@FunctionalInterface
interface ReportProcessor {
public void process(OutputStream outputStream);
}
@Component
public class InventoryReportProcessor implement ReportProcessor {
@Value("${reportGenerator.path}")
private String destinationFileToSave;
/*
@PostConstruct
public void init() {
System.out.println(destinationFileToSave);
}
*/
@Override
public Map<String, Long> process(ByteArrayOutputStream outputStream) throws IOException {
System.out.println(destinationFileToSave);
// Some data processing in here
return null;
}
}
我从
使用它@Service
public class ReportService {
@Value("${mws.appVersion}")
private String appVersion;
/* Other initialization and public API methods*/
@Scheduled(cron = "*/10 * * * * *")
public void processReport() {
InventoryReportProcessor reportProcessor = new InventoryReportProcessor();
Map<String, Long> skus = reportProcessor.process(new ByteArrayOutputStream());
}
}
我的困惑来自以下事实:@Value
中的Service
可以正常工作,但是在@Component
中它返回null
,除非在@PostConstruct
中调用。另外,如果调用@PostConstruct
,则该值在其余的类代码中仍为null
。
我发现了类似的Q&A,并且在Srping docs进行了研究,但到目前为止,还没有一个单一的想法为什么它会以这种方式起作用,什么可以作为解决方案?
答案 0 :(得分:2)
您需要自动装配组件,以使Spring应用程序知道该组件。
@Service
public class ReportService {
@Value("${mws.appVersion}")
private String appVersion;
/* Other initialization and public API methods*/
@Autowired
private ReportProcessor reportProcessor;
@Scheduled(cron = "*/10 * * * * *")
public void processReport() {
//InventoryReportProcessor reportProcessor = new InventoryReportProcessor();
Map<String, Long> skus = reportProcessor.process(new ByteArrayOutputStream());
}
}
答案 1 :(得分:2)
在构造对象之后进行字段注入,因为显然容器无法设置不存在的属性。
当时的System.out.println(destinationFileToSave);触发器值未注入;
如果您希望它能正常工作,请尝试类似的操作
@Autowired
InventoryReportProcessor pross;
pross.process(ByteArrayOutputStream outputStream);
@PostConstruct在对象创建后被调用时起作用。
答案 2 :(得分:0)
Spring只会在已知的bean上解析@Value
注释。您使用的代码会在Spring范围之外创建该类的实例,因此Spring对此不会采取任何措施。
您可以做的一件事是显式创建实例或使用Autowire:
@Autowired
private ReportProcessor reportProcessor;
tl:dr 如果正确配置了应用程序上下文,则@Value
不能为 null ,因为这将停止正确启动应用程序。 / p>
更改您的代码
@Value("${reportGenerator.path}")
private String destinationFileToSave;
到
@Value("${reportGenerator.path}")
public void setDestinationFileToSave(String destinationFileToSave) {
SendMessageController.destinationFileToSave = destinationFileToSave;
}