java - 工厂方法中的依赖注入(inject)导致 NullPointerException

标签 java spring spring-boot factory autowired

我正在使用 Spring Boot 并尝试在其中实现工厂设计模式。问题是,当 QuarterLevelStudentInternshipQuarterLevelMou 的对象被创建时,在这些类中声明的 Autowiring 依赖项被设置为 null,所以它抛出我 NullPointerException.

表单操作

我创建了一个界面。

public interface FormOperation {

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

    public  Object fetchCurrentTargetLevel(long levelId);
}

QuarterLevelStudentInternship

这个类实现了FormOperation接口(interface)

@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接口(interface)

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

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;

    }
}

最佳答案

您在 FormOperationFactory 类中创建的 FormOperation 实例不是 Spring Beans,而只是使用 new 运算符创建的 Java 对象。
此外,这些类(QuarterLevelMou 和 QuarterLevelStudentInternship)定义了 Spring 依赖项,但也没有定义为 Spring beans。

重要的是 Spring 依赖 Autowiring 被设计为与 Spring bean 一起工作

关于您的要求,您应该注意 FormOperation 子类是不可变的。我不明白为什么每次调用工厂方法时都需要创建一个新实例。
相反,你不能让他们成为单例。

因此,我建议您将工厂及其实例化为 Spring 单例的类。
然后在 FormOperationFactory 中,注入(inject)工厂必须创建的两个实例。 最后在工厂方法中根据客户端传递的参数返回一个或另一个实例。

@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 的对象中注入(inject)依赖项,您可以按照@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;
    }
}

关于java - 工厂方法中的依赖注入(inject)导致 NullPointerException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49205859/

相关文章:

java - Intellij 不更新 spring.datasource.url

java - 需要显示响应,它是 View 页面上的 html 代码

Spring 启动 : read list from yaml using @Value or @ConfigurationProperties

java - 当属性丢失时 Spring Boot 不会失败

Java persistancemanager获取返回较少的实体

java - 关闭套接字

java - junit 5 运行所有断言,即使有一个失败

spring - @Component Bean 的 @RequestMapping

java - 从 java -jar 运行 spring boot 应用程序时未提交事务

java - 简单的代码 - 错误让我发疯... float 到 2 字节并返回