工厂方法中的依赖注入导致 NullPointerException
dependency injection in factory method causes NullPointerException
我正在使用 Spring Boot
并尝试在其中实施工厂设计模式。问题是,当 QuarterLevelStudentInternship
和 QuarterLevelMou
的对象被创建时,那些 classes 中声明的自动装配依赖项被设置为空,所以它抛出我 NullPointerException
.
表单操作
我创建了一个界面。
public interface FormOperation {
public Map<String, Object> fetchLevelsInfo(long levelId);
public Object fetchCurrentTargetLevel(long levelId);
}
QuarterLevelStudentInternship
这个class实现了FormOperation接口
@Component
public class QuarterLevelStudentInternship implements FormOperation {
@Autowired /*@Lazy*/
StudentInternshipService internshipService;
@Autowired /*@Lazy*/
StudentInternshipRecordService internshipRecordService;
// these two objects are showing null at the time of object generation and cause null pointer exception
@Override
public Map<String, Object> fetchLevelsInfo(long levelId) {
HashMap<String, Object> levels = new HashMap<>();
levels.put("internshipDetails", internshipService.fetchStudentInternship(levelId));
List<Map<String, Object>> internshipRecord = internshipRecordService.fetchStudentInternshipRecords(levelId);
levels.put("internshipRecord", internshipRecord);
levels.put("internshipGraph", internshipRecordService.fetchInternshipRecordsGroupbyOrganization(levelId));
levels.put("currentTargetLevel", internshipRecord.size());
return levels;
}
@Override
public Object fetchCurrentTargetLevel(long levelId) {
List<Map<String, Object>> internshipRecord = internshipRecordService.fetchStudentInternshipRecords(levelId);
return internshipRecord.size();
}
}
QuarterLevelMou
这个class实现了FormOperation接口
@Component
public class QuarterLevelMou implements FormOperation {
@Autowired /*@Lazy*/
MouServices mouService;
@Override
public Map<String, Object> fetchLevelsInfo(long levelId) {
HashMap<String, Object> levels = new HashMap<>();
List<Map<String, Object>> mouRecord = mouService.fetchMouResult(levelId);
levels.put("mouDetails", mouRecord);
levels.put("currentTargetLevel", mouRecord.size());
return levels;
}
@Override
public Object fetchCurrentTargetLevel(long levelId) {
List<Map<String, Object>> mouRecord = mouService.fetchMouResult(levelId);
return mouRecord.size();
}
}
FormOperationFactory
这是一个根据 evidanceForm
生成对象的工厂 class
@Component
public class FormOperationFactory {
public FormOperation createFormOperation(String evidanceForm) {
if (evidanceForm.equals("Student Internship Form"))
return new QuarterLevelStudentInternship();
else if (evidanceForm.equals("MOUS"))
return new QuarterLevelMou();
return null;
}
}
QuarterLevelOperations
这是我的服务class
@Service("quarterLevelOperations")
@Transactional
public class QuarterLevelOperations {
@Autowired @Lazy
QuarterLevelResultService resultService;
public List<Map<String, Object>> fetchLevelsInfoForForms(
List<Map<String, Object>> quarterLevels, String evidanceForm,
String year, boolean direction, Long quarterId) {
FormOperationFactory formOperationFactory = new FormOperationFactory();
for(Map<String, Object> levels :quarterLevels) {
//quarterLevels.forEach(levels -> {
long levelId = Long.parseLong(levels.get("id").toString());
if (evidanceForm == null) {
levels.put("evidance", resultService.fetchQuaterLevelResultEvidance(levelId));
}
else if (evidanceForm.equals("Student Internship Form")) {
FormOperation operation = formOperationFactory.createFormOperation(evidanceForm);
levels.putAll(operation.fetchLevelsInfo(levelId));
}
else if (evidanceForm.equals("MOUS")) {
FormOperation operation = formOperationFactory.createFormOperation(evidanceForm);
levels.putAll(operation.fetchLevelsInfo(levelId));
}
} //);
return quarterLevels;
}
}
您在 FormOperationFactory
class 中创建的 FormOperation
实例不是 Spring Beans,而只是使用 [=16= 创建的 Java 个对象] 运算符。
此外,这些 classes(QuarterLevelMou 和 QuarterLevelStudentInternship)定义了 Spring 依赖项,但也没有定义为 Spring beans。
重要的是 Spring 依赖自动装配被设计为与 Spring bean 一起工作。
关于您的要求,您应该注意 FormOperation
subclasses 是不可变的。我不明白为什么你需要在每次调用工厂方法时创建一个新实例。
相反,你不能让他们成为单身人士。
所以我建议你将工厂和它实例化的 classes 作为 Spring 单例。
然后在FormOperationFactory
中,注入工厂要创建的两个实例。
最后在工厂方法中 return 根据客户端传递的参数选择一个或另一个实例。
@Component
public class FormOperationFactory {
@Autowired
private QuarterLevelMou quarterLevelMou;
@Autowired
private QuarterLevelStudentInternship quarterLevelStudentInternship ;
public FormOperation createFormOperation(String evidanceForm) {
if (evidanceForm.equals("Student Internship Form"))
return quarterLevelStudentInternship;
else if (evidanceForm.equals("MOUS"))
return quarterLevelMou;
return null;
}
}
并且:
@Component
public class QuarterLevelMou implements FormOperation { ...}
并且:
@Component
public class QuarterLevelStudentInternship implements FormOperation {
此外,由于您确实需要在不是 Spring bean 的对象中注入依赖项,您可以按照@Simon Berthiaume 的建议 inject a AutowireCapableBeanFactory
instance in your factory bean and to use it to inject dependencies。
例如:
@Component
public class FormOperationFactory {
@Autowired
private AutowireCapableBeanFactory beanFactory;
public FormOperation createFormOperation(String evidanceForm) {
FormOperation formOperation = null;
if (evidanceForm.equals("Student Internship Form"))
formOperation = new QuarterLevelStudentInternship();
else if (evidanceForm.equals("MOUS"))
formOperation = new QuarterLevelMou();
if (formOperation != null){
beanFactory.autowireBean(formOperation);
}
return formOperation;
}
}
正如@davidxxx 建议的那样,我以 spring 的方式解决了这个问题。
它正在工作。
@Component("quarterLevelStudentInternship")
public class QuarterLevelStudentInternship implements FormOperation {....}
@Component("quarterLevelMou")
public class QuarterLevelMou implements FormOperation {.....}
@Service("quarterLevelOperations")
@Transactional
public class QuarterLevelOperations {
@Autowired /*@Lazy*/
@Qualifier("quarterLevelStudentInternship")
FormOperation internshipOperation;
@Autowired /*@Lazy*/
@Qualifier("quarterLevelMou")
FormOperation mouOperation;
@Autowired @Lazy
QuarterLevelResultService resultService;
public List<Map<String, Object>> fetchLevelsInfoForForms(
List<Map<String, Object>> quarterLevels, String evidanceForm,
String year, boolean direction, Long quarterId) {
for(Map<String, Object> levels :quarterLevels) {
long levelId = Long.parseLong(levels.get("id").toString());
if (evidanceForm == null) {
levels.put("evidance", resultService.fetchQuaterLevelResultEvidance(levelId));
}
else if (evidanceForm.equals("Student Internship Form")) {
levels.putAll(internshipOperation.fetchLevelsInfo(levelId));
}
else if (evidanceForm.equals("MOUS")) {
levels.putAll(mouOperation.fetchLevelsInfo(levelId));
}
}
return quarterLevels;
}
}
我正在使用 Spring Boot
并尝试在其中实施工厂设计模式。问题是,当 QuarterLevelStudentInternship
和 QuarterLevelMou
的对象被创建时,那些 classes 中声明的自动装配依赖项被设置为空,所以它抛出我 NullPointerException
.
表单操作
我创建了一个界面。
public interface FormOperation {
public Map<String, Object> fetchLevelsInfo(long levelId);
public Object fetchCurrentTargetLevel(long levelId);
}
QuarterLevelStudentInternship
这个class实现了FormOperation接口
@Component
public class QuarterLevelStudentInternship implements FormOperation {
@Autowired /*@Lazy*/
StudentInternshipService internshipService;
@Autowired /*@Lazy*/
StudentInternshipRecordService internshipRecordService;
// these two objects are showing null at the time of object generation and cause null pointer exception
@Override
public Map<String, Object> fetchLevelsInfo(long levelId) {
HashMap<String, Object> levels = new HashMap<>();
levels.put("internshipDetails", internshipService.fetchStudentInternship(levelId));
List<Map<String, Object>> internshipRecord = internshipRecordService.fetchStudentInternshipRecords(levelId);
levels.put("internshipRecord", internshipRecord);
levels.put("internshipGraph", internshipRecordService.fetchInternshipRecordsGroupbyOrganization(levelId));
levels.put("currentTargetLevel", internshipRecord.size());
return levels;
}
@Override
public Object fetchCurrentTargetLevel(long levelId) {
List<Map<String, Object>> internshipRecord = internshipRecordService.fetchStudentInternshipRecords(levelId);
return internshipRecord.size();
}
}
QuarterLevelMou
这个class实现了FormOperation接口
@Component
public class QuarterLevelMou implements FormOperation {
@Autowired /*@Lazy*/
MouServices mouService;
@Override
public Map<String, Object> fetchLevelsInfo(long levelId) {
HashMap<String, Object> levels = new HashMap<>();
List<Map<String, Object>> mouRecord = mouService.fetchMouResult(levelId);
levels.put("mouDetails", mouRecord);
levels.put("currentTargetLevel", mouRecord.size());
return levels;
}
@Override
public Object fetchCurrentTargetLevel(long levelId) {
List<Map<String, Object>> mouRecord = mouService.fetchMouResult(levelId);
return mouRecord.size();
}
}
FormOperationFactory
这是一个根据 evidanceForm
生成对象的工厂 class@Component
public class FormOperationFactory {
public FormOperation createFormOperation(String evidanceForm) {
if (evidanceForm.equals("Student Internship Form"))
return new QuarterLevelStudentInternship();
else if (evidanceForm.equals("MOUS"))
return new QuarterLevelMou();
return null;
}
}
QuarterLevelOperations
这是我的服务class
@Service("quarterLevelOperations")
@Transactional
public class QuarterLevelOperations {
@Autowired @Lazy
QuarterLevelResultService resultService;
public List<Map<String, Object>> fetchLevelsInfoForForms(
List<Map<String, Object>> quarterLevels, String evidanceForm,
String year, boolean direction, Long quarterId) {
FormOperationFactory formOperationFactory = new FormOperationFactory();
for(Map<String, Object> levels :quarterLevels) {
//quarterLevels.forEach(levels -> {
long levelId = Long.parseLong(levels.get("id").toString());
if (evidanceForm == null) {
levels.put("evidance", resultService.fetchQuaterLevelResultEvidance(levelId));
}
else if (evidanceForm.equals("Student Internship Form")) {
FormOperation operation = formOperationFactory.createFormOperation(evidanceForm);
levels.putAll(operation.fetchLevelsInfo(levelId));
}
else if (evidanceForm.equals("MOUS")) {
FormOperation operation = formOperationFactory.createFormOperation(evidanceForm);
levels.putAll(operation.fetchLevelsInfo(levelId));
}
} //);
return quarterLevels;
}
}
您在 FormOperationFactory
class 中创建的 FormOperation
实例不是 Spring Beans,而只是使用 [=16= 创建的 Java 个对象] 运算符。
此外,这些 classes(QuarterLevelMou 和 QuarterLevelStudentInternship)定义了 Spring 依赖项,但也没有定义为 Spring beans。
重要的是 Spring 依赖自动装配被设计为与 Spring bean 一起工作。
关于您的要求,您应该注意 FormOperation
subclasses 是不可变的。我不明白为什么你需要在每次调用工厂方法时创建一个新实例。
相反,你不能让他们成为单身人士。
所以我建议你将工厂和它实例化的 classes 作为 Spring 单例。
然后在FormOperationFactory
中,注入工厂要创建的两个实例。
最后在工厂方法中 return 根据客户端传递的参数选择一个或另一个实例。
@Component
public class FormOperationFactory {
@Autowired
private QuarterLevelMou quarterLevelMou;
@Autowired
private QuarterLevelStudentInternship quarterLevelStudentInternship ;
public FormOperation createFormOperation(String evidanceForm) {
if (evidanceForm.equals("Student Internship Form"))
return quarterLevelStudentInternship;
else if (evidanceForm.equals("MOUS"))
return quarterLevelMou;
return null;
}
}
并且:
@Component
public class QuarterLevelMou implements FormOperation { ...}
并且:
@Component
public class QuarterLevelStudentInternship implements FormOperation {
此外,由于您确实需要在不是 Spring bean 的对象中注入依赖项,您可以按照@Simon Berthiaume 的建议 inject a AutowireCapableBeanFactory
instance in your factory bean and to use it to inject dependencies。
例如:
@Component
public class FormOperationFactory {
@Autowired
private AutowireCapableBeanFactory beanFactory;
public FormOperation createFormOperation(String evidanceForm) {
FormOperation formOperation = null;
if (evidanceForm.equals("Student Internship Form"))
formOperation = new QuarterLevelStudentInternship();
else if (evidanceForm.equals("MOUS"))
formOperation = new QuarterLevelMou();
if (formOperation != null){
beanFactory.autowireBean(formOperation);
}
return formOperation;
}
}
正如@davidxxx 建议的那样,我以 spring 的方式解决了这个问题。 它正在工作。
@Component("quarterLevelStudentInternship")
public class QuarterLevelStudentInternship implements FormOperation {....}
@Component("quarterLevelMou")
public class QuarterLevelMou implements FormOperation {.....}
@Service("quarterLevelOperations")
@Transactional
public class QuarterLevelOperations {
@Autowired /*@Lazy*/
@Qualifier("quarterLevelStudentInternship")
FormOperation internshipOperation;
@Autowired /*@Lazy*/
@Qualifier("quarterLevelMou")
FormOperation mouOperation;
@Autowired @Lazy
QuarterLevelResultService resultService;
public List<Map<String, Object>> fetchLevelsInfoForForms(
List<Map<String, Object>> quarterLevels, String evidanceForm,
String year, boolean direction, Long quarterId) {
for(Map<String, Object> levels :quarterLevels) {
long levelId = Long.parseLong(levels.get("id").toString());
if (evidanceForm == null) {
levels.put("evidance", resultService.fetchQuaterLevelResultEvidance(levelId));
}
else if (evidanceForm.equals("Student Internship Form")) {
levels.putAll(internshipOperation.fetchLevelsInfo(levelId));
}
else if (evidanceForm.equals("MOUS")) {
levels.putAll(mouOperation.fetchLevelsInfo(levelId));
}
}
return quarterLevels;
}
}