본문 바로가기

Java Programming/Spring+Mybatis

[spring] spring4 어노테이션과 빈 등록 및 애플리케이션컨텍스트 설명

스프링 프로젝트를 진행하면 여러가지 어노테이션들을 볼 수 있다.


@Component, @Controller, @Service, @Repository 등.


어느 상황에 위 어노테이션들이 쓰이고 각각 어떤 특징이 있는지 찾아봤다.



1. @Component 어노테이션은 자바 클래스를 스프링 빈이라고 표시하는 역할을 한다. 이 어노테이션을 사용함으로써 스프링의 component-scanning 기술이 이 클래스를 어플리케이션 컨텍스트에 빈으로 등록하게 된다. 


2. @Repository 어노테이션은 DAO에 특화된 어노테이션이다. @Component 어노테이션을 써도 상관없지만, DAO 클래스들에 @Repository 어노테이션을 사용함으로써 @Component 어노테션이 가진 특성과 함께, DAO의 메소드에서 발생할 수 있는 unchecked exception들을 스프링의 DataAccessException으로 처리할 수 있는 장점 또한 갖을 수 있다.


3. @Service 어노테이션은 서비스 레이어 클래스들에 사용되어지는 어노테이션이다. 역시나 @Component 어노테이션을 사용해도 상관없다. @Service 어노테이션을 사용함으로써 해당 클래스가 서비스 레이어 클래스라는 것을 명확하게 할 수 있다. 현재는 @Repository 어노테이션 처럼 추가적인 behavior는 없지만, 추후에 추가될 예정이다.


4. @Controller 어노테이션은 MVC 패턴에서 Controller 클래스에 선언되어진다. 이 또한 @Component 로 대체할 수 있다. 하지만, @Controller 어노테이션을 사용함으로써 @RequestMapping 등의 추가적인 어노테이션을 사용할 수 있게 된다.


실제 프로젝트에서 @Component가 필요한 비슷한 상황들을 직면하곤 한다. 하지만, 대부분의 상황에서 우리는 @Repository, @Service, @Controller 어노테이션을 사용하는게 좋다. @Component 어노테이션은 Controller, Service, Dao 세가지 카테고리 이외의 클래스에만 사용해야 한다.




위 4가지 어노테이션이 선언된 클래스들은 Spring의 DI컨테이너에 의해 스캔되어져 빈으로 등록된 후에만 사용 가능하다. 스캔이 가능하게 하기 위해서 우리는 "context:component-scan" 태그를 applicationContext.xml 파일에 선언해줘야 한다.


 

1
2
3
<context:component-scan base-package="com.howtodoinjava.demo.service" />
<context:component-scan base-package="com.howtodoinjava.demo.dao" />
<context:component-scan base-package="com.howtodoinjava.demo.controller" /
cs


이 태그는 base-package 어트리뷰트를 요구한다. 이름에서 알 수 있듯이, 이 어트리뷰트에 선언된 패키지를 시작점으로 하여 recursive하게 component를 찾게된다. 최상위 패키지를 등록하여 해당 패키지 아래의 모든 클래스를 스프링이 스캔하길 원하진 않겠지. 위 예제처럼, 3개의 component-scan을 선언함으로써, 각각 다른 패키지에서 필요한 빈들을 찾도록 하는것이 좋다.


component-scan 태그를 선언하게되면, context:annotation-config 태그는 필요 없어진다. 



* 이하 내용 : 위 4가지 어노테이션은 interface가 아닌, class에 사용한다.



* @RequestMapping 관련 :


위 내용대로 하면 requestMapping 된 URI가 없다며 오류가 난다. 왜지?


이전에 정리했던건데 왜 내용을 참고하면 <mvc:annotation-driven /> 태그가 필요하다.

<context:component-scan ... />을 선언하면 @Controller, @Repository, @Service, @Component 어노테이션이 선언된 클래스를 빈으로 등록한다.

그리고 @RequestMapping 어노테이션을 통해 URI Mapping을 하려면 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping 빈 설정이

필요한데, Outsider 님의 블로그 글을 참조하면 아래와 같은 설명이 있다.


스프링의 과거 버전에서는 들어오는 웹 요청을 적절한 핸들러에 매칭하기 위해 사용자들이 웹 어플리케이션 컨텍스트에 하나 이상의 HandlerMapping 빈을 정의해야 했다.
어노테이션이 붙은 컨트롤러의 도입으로 RequestMappingHandlerMapping이 자동으로 모든 @Controller 빈의 @RequestMapping 어노테이션을 검색하므로 보통은 사용자가 HandlerMapping 빈을 정의할 필요가 없다. 
즉, 필요에 따라 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping 빈 설정을 해야 URI 맵핑이 가능했는데,

@Controller 어노테이션이 사용되면서 더이상 HandlerMapping 빈 정의가 필요 없어졌고, 이런 설정을 자동으로 해 주는 <mvc:annotation-driven /> 태그가 생기게 된 것 같다.

자료를 찾아보니 이 태그는 스프링 3.0 부터 새로 나온것 같다.

더 자세히 들어가면 <annotation-driven /> 태그가 HandlerMapping 하나만 설정해주는건 아니다. 그 외, 다양한 설정을 더 해주는데 이건 궁금할때 찾아보면 될 듯하다.


정리하자면, 스프링 3.0 부터는 <context:component-scan .. /> 과 함께 <annotation-driven /> 을 선언해줘야 한다.

 <annotation-driven /> : URI RequestMapping => @RequestMapping 사용

<context:component-scan .. />  : @Controller, @Component, @Repository, @Service 등의 어노테이션을 참조하여 빈 등록

스프링에서 말하는 서블릿 애플리케이션 컨텍스트가 서블릿 컨텍스트인가요?


일단 용어를 정리해야 하는데 서블릿 애플리케이션 컨텍스트가 아니고 (아마도) 웹 애플리케이션 컨텍스트를 말씀하신 것 같네요. 웹 애플리케이션 컨텍스트는 서블릿 컨텍스트와 관련은 있지만 개념은 전혀 다릅니다.

스프링에서 말하는 "애플리케이션 컨텍스트"는 스프링이 관리하는 빈들이 담겨 있는 컨테이너라고 생각하시면 됩니다. 스프링 안에는 여러 종류의 애플리케이션 컨텍스트 구현체가 있는데, ApplicationContext라는 인터페이스를 구현한 객체들이 다 이 애플리케이션 컨텍스트입니다. 웹 애플리케이션 컨텍스트는 ApplicationContext를 확장한 WebApplicationContext 인터페이스의 구현체를 말합니다. WebApplicationContext는 ApplicationContext에 getServletContext() 메서드가 추가된 인터페이스입니다. 이 메서드를 호출하면 서블릿 컨텍스트를 반환됩니다. 결국 웹 애플리케이션 컨텍스트는 스프링 애플리케이션 컨텍스트의 변종이면서 서블릿 컨텍스트와 연관 관계에 있다는 정도로 정리가 됩니다. 이 메서드가 추가됨과 동시에 서블릿 컨텍스트를 이용한 몇가지 빈 생애 주기 스코프(애플리케이션, 리퀘스트, 세션 등)가 추가되기도 합니다.

스프링에서, 필수는 아니지만, 웹 애플리케이션을 구성할 때, 도메인과 관련된 빈들은 루트 애플리케이션 컨텍스트에 등록하고 웹과 관련된 UI 성 빈(주로 Controller)은 웹 애플리케이션 컨텍스트라는 별도의 애플리케인션 컨텍스트에 등록해서 사용합니다.

이렇게 분리를 하면 루트 애플리케이션 컨텍스트와 웹 애플리케이션 컨텍스트과 부모 자식 관계가 되는데 웹 애플리케이션 컨텍스트의 빈들은 루트 애플리케이션 컨텍스트의 빈들 주입 받을 수 있지만 거꾸로 루트 애플리케이션 컨텍스트의 빈은 웹 애플리케이션 컨텍스트 같은 자식 애플리케이션 컨텍스트의 빈을 주입 받을 수 없습니다.

이렇게 분리함으로써 Web 기술과 도메인이 분리되는 장점도 있지만, 의존 방향이 역전되거나(도메인이 웹에 의존하는 상황) 상호 의존하는 상황을 막아기도 하고, AOP가 적용되는 범위를 제한하는 등의 이점이 있습니다.


출처 : https://m.blog.naver.com/PostView.nhn?blogId=writer0713&logNo=220695884239&proxyReferer=https%3A%2F%2Fwww.google.co.kr%2F

출처 : https://www.slipp.net/questions/166