Springboot를 사용할 때 대부분, 인터페이스를 이용한 @Service 빈주입을 한다. 하지만 왜 하는지는 모르는채 사용만 했었는데, 백기선님의 유튜브 영상을 보고 깨닫게 되었다.
영상 : https://www.youtube.com/watch?v=C6nsjqrCJq4&feature=youtu.be
서비스 코드
public interface MyService {
void doSomething();
}
@Service
public class MyServiceImpl implements MyService {
@Override
public void doSomething() {
System.out.println("hello Im Impl Service");
}
}
이렇게 서비스가 있는경우를 생각해보자.
Controller 에서는 Service를 두가지 방법으로 주입 받을 수 있다.
1. MyService 를 타입으로 하는 (인터페이스 타입) 빈주입
2. MyServiceImpl 을 타입으로 하는 (클래스 타입) 빈주입
application properties를 이용하여 spring.aop의 proxy-target-class를 false로 설정할 경우엔 클래스를 이용한 @Service 빈 주입을 할 수 없음을 상기하자
spring.aop.proxy-target-class=false
# spring의 기본 설정은 true이다.
결론부터 말하면 인터페이스 서비스로 빈 주입을 해야하는 이유는 spring proxy라고 할 수 있다.
spring proxy는 상속을 이용하여 프록시를 생성하는데, class service는 상속을 받아서 프록시를 만드는 과정에서 빈을 만들다가 에러가 난다.
- 사용자가 service class를 final로 설정해버리거나,
- 생성자를 private으로 생성하여 자식인 프록시가 부모 생성자를 찾지 못하는 경우
1. MyService 를 타입으로 하는 (인터페이스 타입) 빈주입
@Autowired
private MyService myService;
구현 상속 관계 : MyService ---> MyserviceImpl
프록시 상속 관계 : Myservice ---> ProxyMyService
따라서 ProxyMyService 가 인터페이스인 MyService를 상속받는다.
2. MyServiceImpl 을 타입으로 하는 (클래스 타입) 빈주입
@Autowired
private MyServiceImpl myService;
구현 상속 관계 : MyService ---> MyserviceImpl
프록시 상속 관계 : MyServiceImpl ---> ProxyMyService
이경우에 스프링이 생성하는 프록시가 MyServiceImpl 을 부모로하여 상속을 받는 구조인 것이다.
이런 구조를 가진 상황에서 final 혹은 private 생성자를 이용해서 프록시를 만들지 못하게 되고,
빈 생성시 에러가 난다 (sub classing 에러)
'Develop > Springboot' 카테고리의 다른 글
QueryDSL 슬라이싱 테스트(@DataJpaTest) / Test Bean 등록 (3) | 2020.11.02 |
---|---|
Spring Security OAuth2 Login Flow (6) | 2020.09.15 |
@Valid 를 이용해 @RequestBody 객체 검증하기 (11) | 2020.04.05 |
GCP Cloud Storage + Springboot 연동하기 (2) | 2020.03.01 |
크롤링 테스트를 위한 mock server test 구축 (1) | 2020.01.31 |