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

时间:2018-03-10 05:55:01

标签: java spring spring-boot factory autowired

我正在使用Spring Boot并尝试在其中实现工厂设计模式。问题是,当创建QuarterLevelStudentInternshipQuarterLevelMou的对象时,在这些类中声明的自动连接依赖项将设置为null,因此它会抛出NullPointerException

FormOperation

我创建了一个界面。

public interface FormOperation {

    public  Map<String, Object> fetchLevelsInfo(long levelId);

    public  Object fetchCurrentTargetLevel(long levelId);
}

QuarterLevelStudentInternship

此类实现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

此类实现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生成对象的工厂类

@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

这是我的服务类

@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;

    }
}

2 个答案:

答案 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;
         }
    }