인터페이스 빈 주입을 해야하는 이유

2022. 5. 15. 23:34Spring

왜 인터페이스 빈 주입을 해야할까?

  • 실무에서 개발을 할 때 인터페이스 구현을 받은 클래스에 빈주입을 하고 있는 와중 사수님이 되도록이면 클래스에 빈주입보다는 인터페이스에 빈 주입을 하는것이 확장성에도 좋다고 말씀하셨다...😳 (찾아봐야겠군...)

그렇다면 뭐가 좋은지 찾아보자

전체코드

  • 인터페이스

    public interface MyService {
      void doSomething();
    }
  • 서비스

    @Service
    public class MyserviceImpl implements MyService {
      @Override
      public void doSomething() {
          System.out.println("hello Im Impl Service");
      }
    }
  • application.properties

    spring.aop.proxy-target-class=false

정리

  • 위와 같은 서비스가 있다. 그렇다면 Controller에서 Service를 두 가지 방법으로 주입 받을 수 있다.

    1. MyService 를 타입으로 하는 (인터페이스 타입) 빈주입
    2. MyServiceImpl 을 타입으로 하는 (클래스 타입) 빈주입
  • 또한 properties 파일을 보게되면 proxy-target-class 설정을 false로 하였는데, 다음 설정은 클래스를 이용한 @Service 빈 주입을 할 수 없다는 뜻이다. Spring Boot 에서는 Default 값이 true 이다.

그렇다면 Controller에서는 어떻게 빈 주입을 해야할까?
  • Example Code

    @Autowired
    MyServiceImpl myService;
    @Bean
    ApplicationRunner applicationRunner() {
      return (args) -> {
          myService.doSomthing();
      };
    }
  • 위와 같은 코드에서 빌드를 하게되면 어떻게 될까?
    → 에러가 발생한다. (Why???)

빈 주입 현황

  1. MyService → DefaultMyService
  2. MyService → ProxyMyService
  • ProxyMyServiceMyService 타입이다.
  • DefaultMyServiceMyService 타입이다.
  • 하지만...! ProxyMyServiceDefaultMyService 타입이 아니다.

그렇기 때문에 밑의 코드처럼 MyServiceImpl로 빈 주입을 받아 올 수 없는 것이다.

@Autowired
MyServiceImpl myService;

@Bean
ApplicationRunner applicationRunner() {
    return (args) -> {
        myService.doSomthing();
    };
}
  • 그렇기 때문에 직관적으로 상충이 된다. MyServiceImpl 클래스를 보면 @Service 어노테이션을 붙여서 내가 빈주입을 하겠다. 라고 했는데 에러가 났으니...?
  • 그래서 Spring Boot에서는 spring.aop.proxy-target-class=false 의 코드가 true 로 Default 값으로 되어있다. 그래서 Spring Boot에서 위와 같은 코드를 실행하여도 문제 없다.!!! Spring Boot에서는 MyService → DefaultService → ProxyMyService 로 변경해놓았다. ( spring.aop.proxy-target-class=ture 일 때 )

결론

  1. MyService 타입으로 하는 (인터페이스 타입) 빈 주입
    @Autowired
    private MyService myservice;
  • 구현 상속 관계 : MyService → MyServiceImpl
  • 프록시 상속 관계 : MyService → ProxyMyService
    따라서 ProxyMyService 가 인터페이스인 MyService를 상속 받는다.
  1. MyServiceImpl을 타입으로 하는 (클래스 타입) 빈 주입
    @Autowired
    private MyServiceImpl myService;
  • 구현 상속 관계 : MyService → MyServiceImpl
  • 프록시 상속 관계 : MyServiceImpl → ProxyMyService
  • MyService → DefaultService → ProxyMyService*