我正在使用Spring Boot
并尝试在其中实现工厂设计模式。问题是,当创建QuarterLevelStudentInternship
和QuarterLevelMou
的对象时,在这些类中声明的自动连接依赖项将设置为null,因此它会抛出NullPointerException
。
我创建了一个界面。
public interface FormOperation {
public Map<String, Object> fetchLevelsInfo(long levelId);
public Object fetchCurrentTargetLevel(long levelId);
}
此类实现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();
}
}
此类实现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();
}
}
这是一个基于evidanceForm生成对象的工厂类
@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;
}
}
这是我的服务类
@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;
}
}
答案 0 :(得分:2)
在FormOperation
类中创建的FormOperationFactory
实例不是Spring Beans,而是仅使用new
运算符创建的Java对象。
此外,这些类(QuarterLevelMou和QuarterLevelStudentInternship)定义了Spring依赖项,但也未定义为Spring bean。
所有重要的是, Spring依赖关系自动装配旨在与Spring bean一起使用。
关于您的要求,您应该注意FormOperation
子类是不可变的。我不明白为什么你需要在每次调用工厂方法时创建一个新实例
相反,你不能让他们成为单身人士。
所以我建议你把工厂和那些实例的班级作为春天的单身人士
然后在FormOperationFactory
中,注入工厂必须创建的两个实例。
最后在工厂方法中根据客户端传递的参数返回一个或另一个实例。
@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;
}
}
答案 1 :(得分:0)
正如@davidxxx建议我以春季方式实现这个问题。 它正在发挥作用。
@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;
}
}