SpringBoot使用构造器注入的优点
摘要:如果属性初始化时需要使用Spring注入的对象,则必须使用构造器注入。
首先举个例子:
//正确示范
public class FileServiceImpl implements FileService {
private final FileMetadataMapper fileMetadataMapper;
private final SettingsMapper settingsMapper;
private final String basePath;
@Autowired
public FileServiceImpl(FileMetadataMapper fileMetadataMapper, SettingsMapper settingsMapper) {
this.fileMetadataMapper = fileMetadataMapper;
this.settingsMapper = settingsMapper;
this.basePath = settingsMapper.getValue(Settings.STORAGE_PATH_KEY);
}
}
- 通过构造函数注入FileMetadataMapper和SettingsMapper,这是Spring推荐的注入方式,确保依赖在类实例化时被赋值。
- basePath在构造函数中根据settingsMapper的值进行初始化。
- 因为basePath是final,初始化完成后不会更改,增强了线程安全性和可读性。
- 这种方式避免了依赖注入顺序问题,因为 Spring 会在实例化时确保传入的fileMetadataMapper和settingsMapper是已注入的实例。这种模式更符合依赖注入的最佳实践,避免了可能的空指针异常。
错误示范:
//错误示范
public class FileServiceImpl implements FileService {
@Resource
private FileMetadataMapper fileMetadataMapper;
@Resource
private SettingsMapper settingsMapper;
private String basePath = settingsMapper.getValue(Settings.STORAGE_PATH_KEY); //此时settingsMapper还未注入会导致空指针异常
}
- @Resource注解用于字段注入,这会在Spring实例化FileServiceImpl后再对fileMetadataMapper和settingsMapper赋值。
- basePath的初始化依赖于settingsMapper,但settingsMapper是通过字段注入完成的,因此basePath初始化时settingsMapper可能尚未完成注入,导致NullPointerException。
- 字段注入在某些情况下容易导致依赖顺序问题和测试困难,构造函数注入通常更为安全、清晰。