spring 설정을 하던 도중 <mvc:annotation driven />이 단순히 어노테이션 설정 방식을 사용하겠다는 것 외에 dispatcher-servlet에 대한 설정을 추가할 수 있음을 알게 되었다.
spring-webmvc
라이브러리를 이용해서 설정할 수 있는 것들은 위의 이미지와 같고 하나씩 알아보도록 하겠다.
ref. https://gmlwjd9405.github.io/2018/12/18/spring-annotation-enable.html
@Component
@Controller
@Service
@Repository
)을 확인한 후 Bean 인스턴스로 생성한다.@Autowired
와 @Qualifier Annotation
을 인식할 수 있다.메세지 컨버터는 XML이나 JSON을 이용한 AJAX 기능이나 웹 서비스를 개발할 때 사용할 수 있다.
HTTP 요청 프로퍼티를 모델 오브젝트의 프로퍼티에 개별적으로 바인딩하고 모델 오브젝트를 다시 뷰를 이용해 클라이언트로 보낼 콘텐츠를 만드는 대신, HTTP 요청 메세지 본문과 HTTP 응답 메세지 본문을 통째로 메세지로 다루는 방식이다. 메세지 컨버터는 파라미터의 @RequestBody
와 메소드에 부여한 @ResponseBody
를 이용한다.
자바 Configuration에서 Spring MVC에 의해 만들어진 기본 컨버터를 대체하기 위해 configureMessageConverters()
를 오버라이딩 하거나, 기본 컨버터를 커스텀 마이징하거나 기본 컨버터에 추가적인 컨버터를 더하기 위해 extendMessageConverters()
를 오버라이딩 함으로써 HttpMessageConverter
를 커스텀 마이징할 수 있다.
다음 예제는 기본 ObjectMapper 대신 사용자 정의된 XML 및 Jackson JSON 변환기를 추가한다.
@Configuration
@EnableWebMvc
public class WebConfiguration implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
.indentOutput(true)
.dateFormat(new SimpleDateFormat("yyyy-MM-dd"))
.modulesToInstall(new ParameterNamesModule());
converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
converters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()));
}
}
위의 예제에서 Jackson2ObjectMapperBuilder
는 들여쓰기(indentation enabled), 사용자 지정 데이터 포맷, jackson-module-parameter-names
등록과 함께
MappingJackson2HttpMessageConverter
와 MappingJackson2XmlHttpMessageConverter
를 위한 공통 구성을 작성하는데 사용되며 파라미터 이름을 엑세스하는 것을 지원한다. (Java8에 추가)
이 빌더는 Jackson의 기본 프로퍼티들을 다음 설정을 통해 커스텀 마이징 할 수 있다. :
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
→ disabledMapperFeature.DEFAULT_VIEW_INCLUSION
→ disabled또한 다음과 같은 잘 알려진 모듈이 클래스 경로에서 감지되면 자동으로 등록된다.
jackson-datatype-joda
: Joda-Time 타입을 서포팅한다.jackson-datatype-jsr310
: Java 8 Date and Time API 타입을 서포팅한다.jackson-datatype-jdk8
: Optional과 같은 다른 Java 8 타입을 서포팅한다.jackson-module-kotlin
: Kotlin클래스와 data클래스를 서포팅한다.Jackson XML 지원으로 들여쓰기(indentation)를 활성화 하려면
jackson-dataformat-xml
외에woodstox-core-asl
의존성이 필요하다.
아래와 같은 다른 흥미로운 Jackson 모듈도 활용할 수 있다.
jackson-datatype-money
: javax.money
타입을 지원한다. (비공식적 모듈)jackson-datatype-hibernate
: Hibernate-specific 타입과 프로퍼티를 지원한다. (aspects 지연로딩을 포함한다.)다음은 같은 구성을 XML에서 활성화하는 예이다.
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="objectMapper"/>
</bean>
<bean class="org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter">
<property name="objectMapper" ref="xmlMapper"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<bean id="objectMapper" class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"
p:indentOutput="true"
p:simpleDateFormat="yyyy-MM-dd"
p:modulesToInstall="com.fasterxml.jackson.module.paramnames.ParameterNamesModule"/>
<bean id="xmlMapper" parent="objectMapper" p:createXmlMapper="true"/>
ref. https://develop-log-sj.tistory.com/31
Argument Resolver는 사용자가 컨트롤러의 메서드 인자값으로 임의의 값을 전달하려할 때 사용되며 HandlerMethodArgumentResolver
를 구현한 클래스를 작성함으로써 사용할 수 있다.
HandlerMethodArgumentResolver는 컨트롤러에 들어오는 파라미터를 커스텀 마이징하는데 사용하는데, 컨트롤러에 들어가기 전에 클라이언트로부터 받은 파라미터들을 원하는 것으로 가공해서 컨트롤러로 전달한다.
interface인 HandlerMethodArgumentResolver
를 구현한 클래스를 작성한다.
supportsParameter
메소드를 오버라이딩하여 원하는 타입의 Argument가 존재하는지 검사한 후 true
/false
를 리턴한다.
만약 supportsParameter
의 반환값이 true
일 경우 오버라이딩된 resolveArgument
메소드가 수행되고 ArgumentResolver를 사용하는 메소드에 전달할 값을 반환한다.
java Config에 설정:
WebMvcConfigurer
의 addArgumentResolvers
메소드를 오버라이딩한다.
@Bean
public MyArgumentResolver getMyArgumentResolver(){
return new MyArgumentResolver();
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(getMyArgumentResolver());
}
xml 파일에 설정:
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="아규먼트리졸버클래스"></bean>
</mvc:argument-resolvers>
</mvc:annotation-driven>
ref. Asynchronous Request
Spring MVC는 Servlet 3.0 비동기 요청 처리와 광범위하게 통합되어 있다.
DeferredResult
와 Callable
는 컨트롤러 메소드 내에서 값을 반환하고, 하나의 비동기 반환 값에 대한 기본적인 지원을 제공한다.SSE
와 낮은 수준의 데이터(raw data)
를 포함한 여러 값을 스트리밍 할 수 있다.ref. Asynchronous Requests - Configuration
비동기 request를 처리하기위한 기능은 서블릿 컨테이너 수준에서 활성화되어야 한다. MVC configuration은 비동기 요청에 대한 몇 가지 옵션도 제공한다.
필터와 서블릿 선언은 비동기 요청 처리를 활성화하는 것을 true
로 설정하기 위한 비동기 지원 플래그를 가지고 있다. 또한, ASYNC
javax.servlet.DispatchType
를 처리하기 위해 필터 매핑을 선언해야 한다.
Java Configuration에서, 서블릿 컨테이너를 초기화하기 위해 AbstractAnnotationConfigDispatcherServletInitializer
를 사용할 때, 이는 자동적으로 수행된다.
web.xml
Configuration에서는 <async-supported>true</async-supported>
를 DispatcherServlet
과 Filter
선언에 추가해야한다. 또한 필터 매핑에 <dispatcher>ASYNC</dispatcher>
도 추가해야한다.
MVC configuration에서 비동기 요청 처리와 관련하여 다음의 옵션들을 사용할 수 있다.
configureAsyncSupport
콜백을 WebMvcConfigurer
에서 사용하라.<async-support>
엘리먼트를 <mvc:annotation-driven>
의 하위에 사용하라.다음을 구성할 수 있다.:
AsyncTaskExecutor
를 사용한다.Callable
인스턴스를 실행하기 위해서SimpleAsyncTaskExecutor
으로 설정되므로, 반응형 타입으로 스트리밍하거나 Callable
을 반환하는 컨트롤러 메서드가 있는 경우에는 AsyncTaskExecutor
을 구성할 것을 적극 권장한다.DeferredResultProcessingInterceptor
구현CallableProcessingInterceptor
구현DeferredResult
, ResponseBodyEmitter
, SseEmitter
에 대한 기본적인 타임아웃 값을 정할 수 있다. Callable
에서는 WebAsyncTask
을 사용해 타임아웃 값을 제공 할 수 있다.
근원은 자바 기반의 빌드 도구인 Ant에서 ?
, *
, **
을 이용한 패턴으로 경로를 명시하는 것에서 시작한다.
URL mapping 등 경로를 지정할 때 사용하는 경로 패턴으로 현재는 Spring 등 다양한 곳에서 이용하고 있다.
패턴 | 의미 |
---|---|
? | 1개의 문자와 매칭 |
* | 0개 이상의 문자와 매칭 |
** | 0개 이상의 디렉토리와 매칭 |
스프링은 특정 경로가 Ant 경로 패턴 경로와 일치하는지 여부를 확인할 때 사용하는 AntPathMatcher
클래스를 제공한다. 이 클래스가 가지고 있는 boolean match(String pattern, String path)
메서드를 사용해 path가 Ant패턴인 pattern에 매칭되는지 확인한다.
interface PathMatcher
문자열 기반 경로 일치를 위한 전략 인터페이스.
기본 구현은 AntPathMatcher로, Ant-style 패턴 구문을 지원한다.
class AntPathMatcher
Ant 스타일 경로 패턴을 위한 PathMatcher 구현.
이 매핑 코드의 일부는 Apache Ant로부터 빌려왔다.
?
, *
, **
외에 {spring:[a-z]+}
는 "spring"이라는 이름의 경로 변수로써 regexp [a-z]+
와 일치한다.
패턴과 경로는 둘 다 절대적이거나 둘 다 상대적이어야 서로 일치한다. 따라서 이를 구현하는 사용자는 패턴을 정제하여 사용하는 맥락에서 "/"를 접두사로 사용하기를 권장한다.
패스 매칭과 URL 처리와 관련된 옵션을 커스텀 마이징 할 수 있다. 개별 옵션에 대한 자세한 내용은 PathMatchConfigurer javadoc을 참조하라.
다음은 Java Configuration에서 패스 매칭을 커스텀 마이징 하는 방법에 대해 보여준다.
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer
.setUseTrailingSlashMatch(false)
.setUseRegisteredSuffixPatternMatch(true)
.setPathMatcher(antPathMatcher())
.setUrlPathHelper(urlPathHelper())
.addPathPrefix("/api", HandlerTypePredicate.forAnnotation(RestController.class));
}
@Bean
public UrlPathHelper urlPathHelper() {
//...
}
@Bean
public PathMatcher antPathMatcher() {
//...
}
}
다음 예제는 같은 설정을 XML에서 활성화하는 방법을 보여준다.
<mvc:annotation-driven>
<mvc:path-matching
trailing-slash="false"
registered-suffixes-only="true"
path-helper="pathHelper"
path-matcher="pathMatcher"/>
</mvc:annotation-driven>
<bean id="pathHelper" class="org.example.app.MyPathHelper"/>
<bean id="pathMatcher" class="org.example.app.MyPathMatcher"/>
Argument Resolver가 컨트롤러에 들어오는 파라미터를 가공하는데 사용되었다면, RetunValueHandler는 반대로 리턴 타입으로 판단하여 분기 시킬 수 있다.
즉, 컨트롤러를 실행한 결과값을 처리하는 클래스이다.
RequestMappingHanlderAdapter
에서 전달받은 RetunValueHandler
를 사용하여 핸들러 메서드의 리턴 값을 핸들링한다. 이 때, @ResponseBody
어노테이션이 사용된 핸들러 메서드라면 MessageConverter
를 사용해 리턴 값을 Json 포맷으로 변환한다.
ModelAndViewResolver
가 남아있기는 하나, HandlerMethodReturnValueHandler
를 사용하는 것을 권장한다. HandlerMethodReturnValueHandler
를 우선 검색한 뒤 리턴 된 클래스를 처리하는 핸들러를 찾지못한 경우에만 ModelAndViewResolver
를 검색한다.
작동 방식이나 메서드는 Argument Resolver와 굉장히 유사하다.
boolean supportsReturnType(MethodParameter returnType)
: MethodParameter로 주어진 타입이 이 핸들러가 서포팅 할 수 있는지 판단한다.void handleReturnValue
: supportsReturnType
가 true인 경우에만 해당 메서드가 호출된다. Model
에 어트리뷰트 값을 추가하고, 뷰를 셋팅하거나 ModelAndViewContainer
플래그를 true
셋팅함으로써 해당 응답이 직접 처리되었음을 명시하여 주어진 반환값을 처리한다. <mvc:annotation-driven>
<mvc:return-value-handlers>
<bean class="RequestMappingHanlderAdapter구현체 클래스"/>
<ref bean="customHandler" />
</mvc:return-value-handlers>
</mvc:annotation-driven>
<bean id="customHandler" class="RequestMappingHanlderAdapter구현체 클래스"/>