Spring Java Base Configuration 설정
Spring 설정 첫 블로그 내용에서 언급했다시피 나는 Spring설정을 Java Base 기반으로 구현할 것이다.
0. SpringFramework Version 설정
- pom.xml -> 현재 Spring 재단에서 지정한 Current 으로 설정.
또는 자신이 사용하고자 하는 버전으로 설정
- 단, 3.0 버전 이상으로 설정해야 한다.
- Srping 3.0이상 부터 Java Base 기반 설정을 제공한다.
(http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html
- 7.2.1 Configuration metadata 참조)
- 해당 클래스는 내부적으로 startUp, registDispatcherServlet을 진행함. (고로 WebApplicationInitializer 을 구현할 필요가 없다)
- AbstractAnnotationConfigDispatcherServletInitailizer 을 상속 받으면 @Override 되는 메소드는 아래와 같다.
-> getRootConfigClasses()
= root-config 관련 파일. (xml 기준 root-context.xml)
-> getServletConfigClasses()
= servlet-config 관련 파일. (xml 기준 servlert-context.xml)
-> getServletMapping()
- 추가적으로 Filter 셋팅 처리 진행.
- Filter 셋팅 시 등록할 메소드 구현등...
샘플 소스 : WebAppInitializer.java import javax.servlet.Filter; import org.springframework.web.filter.CharacterEncodingFilter; import org.springframework.web.filter.ShallowEtagHeaderFilter; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; import com.restfulapi.config.appservlet.AppServletConfig; import com.restfulapi.config.appservlet.ServletContextConfig; /** * Spring Dispatcher Servlet Web Application Initializer (web.xml) * @author Choeng SungHyun <public27@naver.com> */ public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { /* //WebApplicationInitializer를 직접구현하는 샘플. 대신에 AbstractAnnotationConfigDispatcherServletInitializer를 사용하기로 함 public class SpringWebAppInitializer implements org.springframework.web.WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { // Create the 'root' Spring application context AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext(); rootContext.register(RootContextConfig.class); // Manage the lifecycle of the root application context servletContext.addListener(new ContextLoaderListener(rootContext)); // Create the dispatcher servlet's Spring application context AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext(); appContext.register(AppServletContextConfig.class); // Register and map the dispatcher servlet ServletRegistration.Dynamic dispatcher = servletContext.addServlet("appServlet", new DispatcherServlet(appContext)); dispatcher.setLoadOnStartup(1); dispatcher.addMapping("/"); } } */
//AbstractAnnotationConfigDispatcherServletInitializer 내부에서 startUp, registDispatcherServlet을 진행함.
@Override protected Class<?>[] getRootConfigClasses() { return new Class<?> [] { DataContextConfig.class, //데이터 베이스 관련 Config RootContextConfig.class //root-context.xml //, 구분으로 N개의 class가 들어갈 수 있음. }; } @Override protected Class<?>[] getServletConfigClasses() { return new Class<?> [] { AppServletConfig.class, ServletContextConfig.class //, 구분으로 N개의 class가 들어갈 수 있음. }; } @Override protected String[] getServletMappings() { return new String[] { "/" }; }
@Override protected Filter[] getServletFilters() { //Dispatcher Servlet 필터를 등록 return new Filter[] { new ShallowEtagHeaderFilter(), getCharacterEncodingFilter() }; }
protected CharacterEncodingFilter getCharacterEncodingFilter() { CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter(); characterEncodingFilter.setEncoding("UTF-8"); characterEncodingFilter.setForceEncoding(true); return characterEncodingFilter; }
} |
2. Config 파일 생성
- getRootConfigClassess에 들어갈 설정. (RootContextConfig.java & DataBaseContextConfig.java)
- root-context.xml => RootConfig.java 로 해당 설정 파일은 ApplicationContextAware를 Runtime 프로파일 설정 가능(propertyHolder)
샘플 소스 : RootContextConfig.java import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.annotation.FilterType; import org.springframework.context.annotation.PropertySource; import org.springframework.stereotype.Controller; import org.springframework.stereotype.Repository; import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.RestController; import com.restfulapi.util.CommonUtils; /** * root 설정용 클래스 * root-context.xml 의 역할을 대신 하거나 보충한다. * @author Cheong SungHyun <public27@naver.com> */ @Configuration @EnableAspectJAutoProxy @ComponentScan( basePackages = "com.restfulapi", useDefaultFilters = false, excludeFilters = { @ComponentScan.Filter(type=FilterType.ANNOTATION, classes = Controller.class), @ComponentScan.Filter(type=FilterType.ANNOTATION, classes = RestController.class) }, includeFilters = { @ComponentScan.Filter(type=FilterType.ANNOTATION, classes = Configuration.class), @ComponentScan.Filter(type=FilterType.ANNOTATION, classes = Repository.class), @ComponentScan.Filter(type=FilterType.ANNOTATION, classes = Service.class) } ) @PropertySource("classpath:/runtimeEnv/config-${spring.profiles.active}.properties") public class RootContextConfig implements ApplicationContextAware { protected static Logger logger = LoggerFactory.getLogger(RootContextConfig.class); protected ApplicationContext applicationContext;
@Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; }
// Runtime 프로파일 설정 가능(propertyHolder) @Bean public PropertyPlaceholderConfigurer propertyPlaceholderConfigurer() { PropertyPlaceholderConfigurer configurer = new PropertyPlaceholderConfigurer(); String activeProfile = CommonUtils.getActiveProfile(); logger.debug("ACTIVE SPRING PROFILE => {}", activeProfile); configurer.setLocations( this.applicationContext.getResource("classpath:/runtimeEnv/config-" + activeProfile + ".properties") ); return configurer; } } |
- Data Base 설정 파일.
샘플 소스 : DataContextConfig.java import javax.sql.DataSource; import org.apache.commons.dbcp2.BasicDataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.transaction.annotation.EnableTransactionManagement; /** * Database Config * @author Cheong SungHyun <public27@naver.com> */ @Configuration @EnableTransactionManagement public class DataContextConfig { @Value("${jdbc.driverClass}") private String jdbcDriverClass;
@Value("${jdbc.url}") private String jdbcUrl;
@Value("${jdbc.username}") private String jdbcUsername;
@Value("${jdbc.password}") private String jdbcPassword;
@Bean(name = "dataSource") public DataSource getDataSource() { BasicDataSource dataSource = new BasicDataSource();
//로그 출력 dataSource.setDriverClassName(jdbcDriverClass); dataSource.setUrl(jdbcUrl); dataSource.setUsername(jdbcUsername); dataSource.setPassword(jdbcPassword);
return dataSource; } } |
샘플 소스 : ServletContextConfig.java import java.nio.charset.Charset; import java.util.List; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.annotation.FilterType; import org.springframework.format.FormatterRegistry; import org.springframework.http.CacheControl; import org.springframework.http.MediaType; import org.springframework.http.converter.ByteArrayHttpMessageConverter; import org.springframework.http.converter.FormHttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.ResourceHttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.stereotype.Controller; import org.springframework.stereotype.Repository; import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; import org.springframework.web.servlet.view.json.MappingJackson2JsonView; import org.springframework.web.servlet.view.xml.MappingJackson2XmlView; import com.restfulapi.framework.converter.StringToJodaDateTimeConverter; import com.restfulapi.framework.converter.StringToJodaLocalDateTimeConverter; import com.restfulapi.util.ApiInterceptor; /** * servlet 설정용 클래스 * servlet-context.xml 의 역할을 대신 하거나 보충한다. * @author Cheong SungHyun <public27@naver.com> */ @Configuration @EnableAspectJAutoProxy //ASPECT 사용을 위함. //extends WebMvcConfigurationSupport - 커스텀하게 구현 //extedns WebMvcConfigurerAdapter - 기본설정으로 구현 @EnableWebMvc //Spring 내부적으로 WebMvcConfigurationSupport 클래스를 환경설정 클래스로 등록하여 Spring MVC 환경을 구성하게됨. //몇몇 구성에 대해서 커스터마이징을 처리. -> WebMvcConfigurerAdapter을 사용 //전면 재구성을 위해서는 EnableWebMvc어노테이션 제거 후 WebMvcConfigurationSupport를 상속받아 재구성 @ComponentScan ( basePackages = "com.restfulapi" ,useDefaultFilters = false // 기본 스캔 전략을 종료. 중요함. ,includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class), @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = RestController.class) } //Controller만 스캔 ,excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class), @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Repository.class), @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Service.class) } //Configuration은 스캔대상에서 제외. Config는 명시적으로 지정 ) public class ServletContextConfig extends WebMvcConfigurerAdapter {
protected static Logger logger = LoggerFactory.getLogger(ServletContextConfig.class);
/** * 리소스 핸들러 설정 * <resources location="/resources/" mapping="/resources/**"> */ @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/css/**").addResourceLocations("/css/") .setCacheControl(CacheControl.maxAge(10, TimeUnit.SECONDS).mustRevalidate()); registry.addResourceHandler("/lib/**").addResourceLocations("/lib/") .setCacheControl(CacheControl.maxAge(10, TimeUnit.SECONDS).mustRevalidate()); registry.addResourceHandler("/web/**").addResourceLocations("/webroot/") .setCacheControl(CacheControl.noStore()); //prevent cache //.setCachePeriod(0); //0: prevent cache }
/** * ViewResolver 등록 */ @Override public void configureViewResolvers(ViewResolverRegistry registry) { MappingJackson2JsonView jsonView = new MappingJackson2JsonView(); jsonView.setPrettyPrint(true);
MappingJackson2XmlView xmlView = new MappingJackson2XmlView(); xmlView.setPrettyPrint(true);
registry.enableContentNegotiation( jsonView ,xmlView ); registry.jsp("/WEB-INF/views/", ".jsp"); super.configureViewResolvers(registry); }
/** * Interceptor 설정 */ @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new ApiInterceptor()); }
/** * Configure content negotiation options. */ @Override public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { //Restful 한 서비스에서 APPLICATION_JSON_VALUE로 지정하여도 충분하나 //IE9에서 JSON을 iframe transport로 전송 시 파일로 저장하려는 버그 발생으로 인해 아래와 같이 선언. MediaType API_PRODUCES_MEDIATYPE = MediaType.valueOf(MediaType.TEXT_HTML_VALUE+";charset=utf-8");
configurer.ignoreAcceptHeader(false) //HttpRequest Header의 Accept 무시 여부 .favorPathExtension(true) //프로퍼티 값을 보고 URL의 확장자에서 리턴 포맷을 결정 여부 .ignoreUnknownPathExtensions(true) //모든 미디어 유형으로 해결할 수없는 경로 확장자를 가진 요청을 무시할지 여부 .favorParameter(true) //URL 호출 시 특정 파라미터로 리턴포맷 전달 허용 여부 ex)a.do?format=json .mediaType("json", MediaType.APPLICATION_JSON_UTF8) //UTF-8 기반 JSON 타입 선언 .defaultContentType(API_PRODUCES_MEDIATYPE); }
/** * Add Converters and Formatters in addition to the ones registered by default. * This implementation is empty. */ @Override public void addFormatters(FormatterRegistry registry) { super.addFormatters(registry); registry.addConverter(new StringToJodaDateTimeConverter()); registry.addConverter(new StringToJodaLocalDateTimeConverter()); }
/** * {@link HttpMessageConverter}를 설정 * 설정시 기본 컨버터 미사용. {@link #addDefaultHttpMessageConverters(List)} * {@link RequestMappingHandlerAdapter}, {@link ExceptionHandlerExceptionResolver}에서 사용. */ @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { converters.add(new ByteArrayHttpMessageConverter()); //바이트 배열 읽기/쓰기. 모든 미디어 타입(*/*)에서 읽고 application/octect-stream으로 쓴다. converters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")){{ setWriteAcceptCharset(true); }}); //모든 미디어 타입(*/*)을 String으로 읽는다. text/plain에 대한 String을 쓴다. converters.add(new ResourceHttpMessageConverter()); //Resource를 읽고 쓰기. converters.add(new FormHttpMessageConverter()); //application/x-www-form-urlencoded. Form data is read from and written into a MultiValueMap. converters.add(new MappingJackson2HttpMessageConverter()); //converters.add(new MappingJackson2XmlHttpMessageConverter()); } } |
- AppServletContextConfig.java 는 Spring 관련 컴포넌트가 아닌 서비스에서 소비하는 컴포넌트에 대한 설정파일로 작성.
- ContorllerLoggingAspect, ObjectMapper 설정, Cache 설정(EHCache), JsonMaker설정, TCP Connection Beans, Factory 설정 등.
샘플 소스 : AppServletContextConfig.java import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.restfulapi.framework.log.ControllerLoggingAspect; /** * Spring 관련 컴포넌트가 아닌 서비스에서 소비하는 컴포넌트에 대한 설정 * @author Cheong SungHyun <public27@naver.com> */ @Configuration public class AppServletConfig { // Controller Logging Aspect @Bean public ControllerLoggingAspect controllerLoggingAspect() { return new ControllerLoggingAspect(); }
// /** MappingJackson ObjectMapper override */ // @Bean(name="objectMapper") // public ObjectMapper objectMapper() { // return null; // } // // /** MappingJackson XmlMapper override */ // @Bean(name="xmlMapper") // public ObjectMapper xmlMapper() { // return null; // } // // Cache 설정 가능 (ehCache) // JsonMaker 설정 가능(Gson등) // TCP Connection beans, factory 설정 가능 (커넥션 풀 사이즈 설정, 연결풀 팩토리 설정, 기본 연결 정보 설정, 연결풀 객체 생성 등)
} |
위 샘플 소스는 참고용 소스이며
중간 중간 유틸성 함수들의 경우 따로 구현해야 한다.
즉, 해당 블로그의 샘플 소스는 완벽하지 않다는 것이다.
(물론 몇 유틸성 함수만 구현하면 정상 작동하는 소스이다.)
샘플 소스는 참고만 하고 자신만의 설정을 구현해야 한다.
오타가 있을 수 있으며 혹 잘못 작성된 내용도 존재할 수 있다.
내 블로그는 완벽하지 못하다.
'Spring Framework > Spring 설정' 카테고리의 다른 글
Spring Java Base Config 사용 준비 및 Dependency 목록 (0) | 2016.09.02 |
---|---|
Spring Framework Java Base 설정 (0) | 2016.09.02 |