工厂方法中的依赖注入导致 NullPointerException

dependency injection in factory method causes NullPointerException

我正在使用 Spring Boot 并尝试在其中实施工厂设计模式。问题是,当 QuarterLevelStudentInternshipQuarterLevelMou 的对象被创建时,那些 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;
         }
    }