@Service 주석은 어디에 보관해야합니까? 인터페이스 또는 구현?


133

Spring을 사용하여 응용 프로그램을 개발 중입니다. @Service주석 을 사용해야합니다 . 나는이 ServiceIServiceImpl같은 그 ServiceImpl implements ServiceI. @Service주석 을 어디에 보관 해야하는지 혼란 스럽습니다 .

인터페이스 또는 구현에 주석을 달아야 @Service합니까? 이 두 방법의 차이점은 무엇입니까?


이는 유사한 게시물에 대한 내 대답입니다 : stackoverflow.com/questions/38618995/...
Agustí 산체스

답변:


140

인터페이스에 쓸모가 없기 때문에 @Component(또는 @Service...) 인터페이스에 넣지 마십시오 . 이유를 설명하겠습니다.

주장 1 : 인터페이스가있는 경우 주 입점 유형에 해당 인터페이스를 사용하려고합니다.

주장 2 : 인터페이스의 목적은 여러 구현으로 구현 될 수있는 계약을 정의하는 것입니다. 다른쪽에는 주입 지점이 있습니다 ( @Autowired). 인터페이스를 하나만 구현하고 클래스를 구현하는 클래스는 (IMHO) 쓸모 없으며 YAGNI를 위반 합니다 .

사실 : 당신이 넣을 때 :

  • @Component@Service인터페이스에서 (또는 ...)
  • 그것을 구현하는 여러 클래스가 있습니다.
  • 최소한 두 개의 클래스가 Spring Beans가되고
  • 유형 기반 주입에 인터페이스를 사용하는 주입 지점이 있고

그리고 당신은 얻을 것이다 NoUniqueBeanDefinitionException (또는 당신은 환경, 프로파일 또는 한정자 ...와 매우 특별한 구성 설정이 ...)

결론 : 당신이 사용하는 경우 @Component(또는 @Service인터페이스에, ...) 다음 두 clains 중 적어도 하나를 위반해야합니다. 따라서 @Component인터페이스 수준에서 사용하는 것은 유용하지 않다고 생각합니다 (일부 드문 경우 제외) .


Spring-Data-JPA 리포지토리 인터페이스는 완전히 다른 것입니다.


3
당신이 쓰는 것이 매우 흥미 롭습니다. 그래서 올바른 방법은 무엇입니까? 인터페이스에 전혀 주석을 달지 않고 구현에 서비스 주석을 제공합니까? Spring은 여전히 ​​인터페이스 유형을 사용하여 자동 배선 할 수 있습니까? this>에 대한 귀하의 답변은 무엇입니까? stackoverflow.com/questions/12899372/…
corlaez

3
질문이 있는데, 클래스를 하나만 구현할 때 왜 서비스 계층에 대한 인터페이스를 만들어야합니까? 많은 프로젝트를 보았습니다. 컨트롤러 레이어, ** 서비스 레이어 ( servicInterface , serviceInterfaceImpl ) 및 리포지토리 레이어가 있습니다.
Yubaraj

4
@Yubaraj : 공정한 요점이지만 귀하의 질문은 다른 주제에 관한 것입니다 (제 답변은 인터페이스가 있고 인터페이스가 아니라 주석을 배치하는 위치에 관한 것입니다). 귀하의 질문에 대해 : 두 가지 구현이 결코없는 비즈니스 서비스 클래스에 대한 인터페이스를 가질 이유가 거의 없습니다. (BTW : 다른 API를 작성하지 않는 한, 언제든지 코드를 리팩터링하고 나중에 필요할 때 인터페이스를 소개 할 수 있습니다)
Ralph

1
@Yubaraj의 인터페이스는 필요할 때 Bean에 경량의 인터페이스 기반 jdk 프록시를 만들 수 있습니다. 인터페이스가 없으면 스프링은 프록시를 만들기 위해 cglib를 사용하여 빈을 서브 클래 싱하거나 수정해야합니다. @TransactionalBean에 대한 프록시가 사용되는 예제 중 하나입니다. AOP는 또 하나입니다.
Yoory N.

1
때로는 구현 클래스가 두 개 이상 없지만 인터페이스에서 내 메소드를 선언하는 것을 선호합니다. 동료 개발자는 구현에 대해 걱정하지 않고 선언과 문서를 확인해야만 사용 가능한 서비스를 쉽게 확인할 수 있습니다.
HFSDev

32

@Service , @Repository , @Component 등의 기본 주석은 모두 동일한 목적을 제공합니다.

주석 기반 구성 및 클래스 경로 스캔 사용시 자동 감지

내 경험에서 나는 항상 사용하고 @Service인터페이스 또는 같은 추상 클래스와 주석에 주석을 @Component하고 @Repository자신의 구현. @Component주석 나는 기본 목적, 간단한 스프링 빈을 제공하는 클래스에서 사용하고 있습니다. 예를 들어 데이터베이스와 통신해야하거나 트랜잭션이있는 경우 등 레이어 @Repository에서 사용중인 주석DAO

따라서 @Service기능에 따라 인터페이스 및 기타 레이어로 인터페이스에 주석을 달 것을 제안 합니다.


10
인터페이스에 주석 달기와 구현에 주석 달기의 차이점이 무엇인지 알 수 있습니까?
TheKojuEffect

27
로부터 봄 문서 , "이 주석은 구현 클래스는, 클래스 패스 스캔을 통해 자동으로 감지 할 수 @Component의 전문화 역할" 이 구현 클래스에 사용하기위한 것 것을 시사한다.
nbrooks

1
@TheKojuEffect,이 게시물은 주석 달기 인터페이스와 구현의 차이점에 대해 자세히 설명합니다.- stackoverflow.com
Mahesh

@ user3257644 해당 게시물의 답변이 제시 한 제안은 일반적으로 모든 주석이 아니라 '@Transactional'주석과 관련이 있습니다.
Jonathan

3
인터페이스의 @service 주석은 다른 스테레오 타입 주석과 마찬가지로 영향을 미치지 않습니다. 모든 고정 관념 주석은 추상 또는 구체적인 클래스에 배치해야합니다.
bigfoot

13

내가 사용 @Component, @Service, @Controller@Repository단지 구현 클래스에 아닌 인터페이스에 주석을. 그러나 @Autowired인터페이스가있는 주석은 여전히 ​​나에게 효과적이었습니다.


7

@Service에 주석을 달면 장점은 그것이 서비스라는 힌트를 준다는 것입니다. 구현 클래스가 기본적 으로이 주석을 상속하는지 여부는 알 수 없습니다.

단점은 스프링 특정 주석을 사용하여 인터페이스를 특정 프레임 워크, 즉 Spring과 연결한다는 것입니다. 인터페이스가 구현에서 분리되어야하므로 프레임 워크 별 주석 또는 인터페이스의 객체 부분을 사용하지 않는 것이 좋습니다.


1
나는 우리가 강한 결합 주장을 여러 번 들었다고 생각하지만, 주석이 jar없이 존재할 수 있다는 것을 기억하십시오. 기본적으로 결합이 주석에있는 한 여전히 분리 될 수 있습니다.
Niels Bech Nielsen

1

스프링의 한 가지 장점은 서비스 (또는 다른) 구현을 쉽게 전환하는 것입니다. 이를 위해 인터페이스에 주석을 달고 다음과 같이 변수를 선언해야합니다.

@Autowired
private MyInterface myVariable;

아니 :

@Autowired
private MyClassImplementationWhichImplementsMyInterface myVariable;

첫 번째 경우와 같이 고유 한 순간부터 주입 할 구현을 활성화 할 수 있습니다 (한 클래스 만 인터페이스를 구현 함). 두 번째 경우에는 모든 코드를 리팩터링해야합니다 (새 클래스 구현에는 다른 이름이 있음). 결과적으로 주석은 인터페이스에 최대한 많이 있어야합니다. 또한 JDK 프록시는 이에 적합합니다. CGlib 프록시와 달리 런타임 유형이 미리 알려져 있기 때문에 응용 프로그램 시작시 생성되고 인스턴스화됩니다.


4
"MyClassImplementationWhichImplementsMyInterface"LOL
inafalcao

첫 번째 예제가 작동하기 위해 인터페이스에 주석을 달지 않아도됩니다. @Service구현에 주석을 달고 인터페이스를 자동 와이어 링 할 수 있습니다. Spring은이 인터페이스를 구현하는 객체를 검사합니다.
Marco

1

나는 @Service당신의 클래스에 넣을 것이지만 인터페이스의 이름을 주석에 대한 매개 변수로 넣습니다.

interface ServiceOne {}

@Service("ServiceOne")
class ServiceOneImpl implements ServiceOne{}

그렇게하면 모든 이점을 얻을 수 있으며 여전히 인터페이스를 주입 할 수 있지만 수업을받을 수 있습니다

@Autowired 
private ServiceOne serviceOne;

따라서 인터페이스가 스프링 프레임 워크에 연결되어 있지 않으므로 언제든지 클래스를 변경할 수 있으며 모든 주입 지점을 업데이트 할 필요는 없습니다.

따라서 구현 클래스를 변경하려면 새 클래스에 주석을 달고 첫 번째 클래스에서 제거 할 수는 있지만 변경 해야하는 전부입니다. 클래스를 주입하면 impl 클래스를 변경하려고 할 때 많은 작업을 수행 할 수 있습니다.


-1

간단히 말해 :

@Service서비스 계층에 대한 스테레오 타입 주석입니다 .

@Repository는 위한 스테레오 주석 인 지속성 층.

@Component 는 Spring에게 Application Context에서 객체의 인스턴스를 생성하도록 지시하는 데 사용되는 일반적인 고정 관념 주석입니다. 인스턴스의 이름을 정의 할 수 있습니다. 기본값은 낙타의 경우 클래스 이름입니다.


3
이러한 주석의 의미는 추구되지 않지만 인터페이스 또는 구현에 주석을 달아야합니다.
nanosoft

-3

봄 콩을 만드는 데 사용할 수있는 5 가지 주석이 있습니다. 아래 답변 목록을 작성하십시오.

정말 인터페이스가 필요합니까? 각 서비스 인터페이스에 대해 하나의 구현을 사용하려면 피하십시오. 클래스 만 사용하십시오. 물론 RMI가 없거나 인터페이스 프록시가 필요한 경우.

@Repository-dao 레이어 클래스를 주입하는 데 사용합니다.

@Service-서비스 계층 클래스를 주입하는 데 사용합니다. 서비스 계층에서도 DB 트랜잭션 관리를 위해 @Transactional 주석을 사용해야 할 수도 있습니다.

@Controller-스프링 빈으로 주입하는 JSF 관리 빈과 같은 프론트 엔드 계층 컨트롤러에 사용합니다.

@RestController-스프링 레스트 컨트롤러에 사용하면 나머지 메소드에 @ResponseBody 및 @RequestBody 주석을 넣을 때마다 피하는 데 도움이됩니다.

@Component-컨트롤러, 서비스 또는 dao 클래스가 아닌 스프링 빈을 주입 해야하는 경우 다른 경우에 사용하십시오


예. 계층의 경계 (예 : 데이터 액세스 계층 및 서비스 계층)에 대한 인터페이스가 필요합니다. 계층 구현을 포함하는 모듈의 느슨한 결합을 가능하게합니다. 그것들이 없으면 언급 된 레이어의 클라이언트는 구체적인 유형을 알아야하고, CachingDao로 BasicDao를 장식하고 싶을 때이를 변경해야합니다.
Igand
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.