[Spring] 주입할 스프링 빈이 없어도 동작해야 할 때가 있다?

soonhankwon·2023년 10월 6일
0
post-thumbnail

어떤 경우에 스프링 빈이 없어도 동작해야 할까?

라는 의문에 생각났던 상황은 테스트 코드 그리고 스프링빈이 외부 API에 의존하고 있는데 외부 API가 일정기간 점검중 과 같은 상황이었습니다.

  • 해당 스프링 빈(기능)이 없어도 애플리케이션은 정상으로 동작해야 할때!

스프링 빈이 없어도 동작하게 하는 방법

일단, 스프링 빈으로 등록하지 않아도 동작하게 하는 방법은 여러가지가 있습니다.

  • @Autowired(required=false)
    • 자동 주입할 대상이 없으면(스프링 빈이 없다면) 수정자 메서드 자체가 호출 안됨
  • @Nullable
    • 자동 주입할 대상이 없으면(스프링 빈이 없다면) null 입력
  • Optional
    • 자동 주입할 대상이 없으면(스프링 빈이 없다면) Optional.empty 입력

Setter & @Autowired

//호출안됨
@Autowired(required = false)
public void setNoBean1(Member member) {
}

//null 호출
@Autowired
public void setNoBean2(@Nullable Member member) {
}

//Optional.empty 호출
@Autowired(required = false)
public void setNoBean3(Optional<Member> member) {
}

외부 API 장애시 @Nullable 또는 Optional 을 사용해서 잠시 해당 기능을 대체하기 (스프링 빈 사용)

위의 방법의 용도는 테스트 코드를 작성할 경우를 제외하고 크게 와닿지 않았습니다.

굳이 setter 를 열어줘야하나?🧐 생각도 들고, 제가 해당하는 상황을 만나지 못했기때문이라고 생각합니다.

하지만 @Nullable or Optional은 상황에 따라 사용할만하다고 생각이 듭니다.

외부 API 사용을 가정한 파일 업로드 서비스 예제를 생각했습니다.

이경우는 생성자 주입을 사용합니다.

  • 파일 업로드 서비스라는 인터페이스를 정의하고 구현 서비스를 만들었습니다.
public interface FileUploadService {
    void uploadFile(String filePath);
}

@Service
public class ExternalApiFileUploadService implements FileUploadService {
    @Override
    public void uploadFile(String filePath) {
        // 외부 API를 사용한 파일 업로드 로직 구현
        System.out.println("외부 API 파일업로드: " + filePath);
    }
}
  • @Nullable 또는 Optional 을 사용해서 해당 기능을 잠시 Off 시켜놓을수 있습니다.
@Component
public class FileUploadSystem {

    private final FileUploadService fileUploadService;

    @Autowired
    public FileUploadController(@Nullable FileUploadService fileUploadService) {
        this.fileUploadService = fileUploadService;
    }

    public void uploadFile(String filePath) {
        if (fileUploadService != null) {
            fileUploadService.uploadFile(filePath);
        } else {
            System.out.println("파일업로드 일시장애로 대체 서비스 작동");
        }
    }
}
  • 또는 대체 스프링빈을 등록해서 fileUploadService 가 null 또는 Optional.empty 일때 대체 스프링빈이 동작하게 로직을 구성할수도 있습니다.
  • 참고로 위와 비슷한 상황에서 Nullable 또는 Optional 을 사용하지 않고 같은 인터페이스를 구현한 스프링 빈을 동적으로 주입해서 사용하는 방법도 있습니다.
    • 아래는 Map을 사용한 빈 동적주입의 예시 입니다.

      @Component
      public class FileUploadSystem {
      
          private final Map<String, FileUploadService> fileUploadServiceMap;
      
          public FileUploadController(Map<String, FileUploadService> fileUploadServiceMap) {
              this.fileUploadServiceMap = fileUploadServiceMap;
          }
      	
          @Override
          public void uploadFile(String filePath, String flag) {
              if (flag.equals("kakao")) {
                  fileUploadServiceMap.get("kakaoFileUploadService");
              } else {
      						fileUploadServiceMap.get("defaultFileUploadService");
              }
          }
      }

Summary.

  • 스프링빈으로 등록하지 않고 @Autowired(required=false) 를 해줘서 사용해야 하는 상황은 테스트 코드를 제외하고 크게 와닿지 않았습니다.
    • @Autowired 옵션을 꺼줘서, 스프링빈으로 등록하지 않은 객체를 사용할 하나의 방법이 있다! 라는 정도로 이해 (true 로 되어있다면 런타임 예외발생 → 스프링빈으로 등록되지 않았음으로)
  • 다만 Nullable, Optional 을 사용해서 동적으로 서비스를 대체하는 방법은 상황에 맞게 사용하면 유용할 것이라고 생각합니다.
profile
ProblemOverFlow

0개의 댓글