Home > Enterprise >  How bad is a service circular reference?
How bad is a service circular reference?

Time:05-25

I have a question and it is related to the error that I am getting. How bad is it really to have a circular reference in my service? I know very well what the error is due to and how to possibly solve it, only that in the company where I work a Senior recommended me that for transactional issues it is necessary to make such a circular reference and in fact it is a very recurrent practice there, but as I am starting a personal project from scratch is the first time I get the error and it triggered the doubt again. Thank you very much in advance!

Circular reference Spring Boot error

Here is the code of the service

public class MedicalRecordServiceImpl implements MedicalRecordService {

    private final MedicalRecordRepository medicalRecordRepository;
    private final MedicalRecordService medicalRecordService;
    private final PatientService patientService;
    private final TutorService tutorService;
    private final MedicalHistoryAnswerService medicalHistoryAnswerService;
    private final DentalHistoryAnswerService dentalHistoryAnswerService;

    public MedicalRecordServiceImpl(MedicalRecordRepository medicalRecordRepository, MedicalRecordService medicalRecordService, PatientService patientService, TutorService tutorService, MedicalHistoryAnswerService medicalHistoryAnswerService, DentalHistoryAnswerService dentalHistoryAnswerService) {
        this.medicalRecordRepository = medicalRecordRepository;
        this.medicalRecordService = medicalRecordService;

        this.patientService = patientService;
        this.tutorService = tutorService;
        this.medicalHistoryAnswerService = medicalHistoryAnswerService;
        this.dentalHistoryAnswerService = dentalHistoryAnswerService;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void saveMedicalRecord(MedicalRecordEntity medicalRecord) {
        medicalRecordRepository.save(medicalRecord);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public ResponseEntity<?> createNewMedicalRecord(MedicalRecordDTO medicalRecordDTO) {

        PatientEntity patient = this.storeMedicalRecordIntoPatient(medicalRecordDTO);
        TutorEntity tutor = this.storeMedicalRecordIntoTutor(medicalRecordDTO);
        List<MedicalHistoryAnswerEntity> medicalHistoryAnswers = this.storeMedicalRecordIntoMedicalHisAns(medicalRecordDTO);
        List<DentalHistoryAnswerEntity> dentalHistoryAnswers = this.storeMedicalRecordIntoDentalHisAns(medicalRecordDTO);

        patientService.savePatient(patient);
        tutor.setPatient(patient);
        tutorService.saveTutor(tutor);

        MedicalRecordEntity medicalRecord = this.createMedicalRecord(patient, tutor);

        medicalRecordService.saveMedicalRecord(medicalRecord);

        medicalHistoryAnswers.forEach(medicalHistoryAnswer -> {
            medicalHistoryAnswer.setMedicalRecord(medicalRecord);
            medicalHistoryAnswerService.saveMedicalHistoryAnswer(medicalHistoryAnswer);
        });

        dentalHistoryAnswers.forEach(dentalHistoryAnswer -> {
            dentalHistoryAnswer.setMedicalRecord(medicalRecord);
            dentalHistoryAnswerService.saveDentalHistoryAnswer(dentalHistoryAnswer);
        });

        return ResponseEntity.status(HttpStatus.OK).body("");
    }
}

CodePudding user response:

The only reason why you may need circular dependency is the case when you what to access to "this" as to a bean to trigger annotated method logic.

For example if you have two methods "foo" (annotated with @Transactional) and "bar" (invokes "foo" within). You will have to use self injection to trigger transaction in case of invocation bar>foo (selfBean.foo() instead of this.foo()).

Also you can use @Lasy for self infection to avoid the circular dependency error.

But it's a pretty ugly solution and you should avoid it if it's possible. It depends on the situation, may be it's possible to split logic to different services or use TransactionTemplate.

CodePudding user response:

As you said, I will assume that you know what the error is and how to resolve it. A circular reference is bad for the following reason:

Spring loads beans the moment you start the project, meaning it loads each bean in the correct order so it can load all beans and references them successfully. If you have a circular reference Spring won't know with which bean to start first, and so the error occurs. It's about how Spring works.

I also had this error in my current project and you are not limited to not making the circular reference, you just need to instruct Spring, so that it knows how to handle each bean in these cases.

CodePudding user response:

Well, imagine this: You get a new phone, you are all excited about it. You want to unlock it, but it protectd with password. The password is available inside the notes in the locked phone.

So, you want to use your phone, for it you need the pass. You want the pass, for it you need to unlock the phone. You want to use your phone, for it you need your pass... Etc.

The same happens when you have circular references, for A you need B, for B you need A, so you cannot create A and cannot create B either and cannot proceed.

  • Related