📌 Java Configuration
기본적으로 프로젝트를 생성하면 모든 web.xml, root-context.xml, app-servlet.xml 세가지의 기본 설정파일이 만들어진다.
Spring Framework 3.1부터는 이러한 xml 설정파일을 Java 기반으로 작성할 수 있도록 각종 클래스와 인터페이스, 어노테이션을 지원하고 있다.
둘 중 어떤 방식을 사용해도 괜찮지만, 다음과 같은 이유로 되도록 Java Config 방식으로 변경해 사용하는 것을 권장한다.
- 더 많은 정보를 얻을 수 있다.
- 컴파일 에러를 얻을 수 있다.
- 설정 변경에 용이하다.
나는 현재 진행하고 있는 프로젝트의 기본 설정을 자바 클래스로 변경하기로 했다.
위와 같은 이유도 있지만, xml과 java config를 섞어 쓰니 헷갈리고 보기에도 좋지 않은 것 같아서(?) 한번 연습해보기로😗
📁 pom.xml
web.xml을 삭제하면 이를 인식하지 못해 pom.xml에 에러 표시가 생긴다.
따라서 플러그인을 추가해 xml을 사용하지 않는다는 설정을 해주어야 한다.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
📁 web.xml
기존에는 web.xml을 통해 설정파일 등록, 디스패처 서블릿 매핑, 필터 등록을 할 수 있었다.
자바 클래스로 변경하기 위해서는 다음 중 하나의 클래스를 상속하고 필요한 메서드를 오버라이딩해야 한다.
- AbstractAnnotationConfigDispatcherServletInitializer
- WebApplicationInitializer
이번 포스팅에서는 전자를 상속했다.
public class WebConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] {RootConfig.class, SecurityConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] {ServletContext.class};
}
@Override
protected String[] getServletMappings() {
return new String[] {"/"};
}
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
return new Filter[] { characterEncodingFilter };
}
}
1) Root Context 설정
xml에서는 contextConfigLocation에 루트 컨텍스트 설정파일 경로를 지정해주었다.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:root-context.xml
classpath:security-context.xml
</param-value>
</context-param>
getRootConfigClasses()
Root Context와 관련된 설정 클래스들을 배열 형태의 리턴값으로 지정한다.
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] {RootConfig.class, SecurityConfig.class};
}
2) Dispatcher Servlet 설정
기존에는 DispatcherServlet 설정파일의 경로를 지정하고 서블릿 이름을 통해 url pattern과 매핑해주었다.
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
getServletConfigClasses()
디스패처 서블릿 설정 클래스들을 배열 형태의 리턴값으로 지정한다.
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] {ServletContext.class};
}
getServletMappings()
위에서 등록한 디스패처 서블릿과 매핑할 url pattern을 설정한다.
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
@Override
protected String[] getServletMappings() {
return new String[] {"/"};
}
3) 필터 설정
필터 클래스와 속성을 서술하고 필터 이름을 통해 매핑해 필터가 적용될 URL을 지정하는 부분이다.
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
getServletFilters()
new 연산자를 이용해 필터 클래스의 인스턴스를 생성하고 등록해준다.
시큐리티 필터 체인은 AbstractSecurityWebApplicationInitializer을 통해 등록해줄 것이므로 따로 작성하지 않았다.
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
return new Filter[] { characterEncodingFilter };
}
📁 root-context.xml
기존의 root-context.xml을 대체할 RootConfig 클래스를 작성한다.
설정파일임을 알려주는 어노테이션 @Configuration을 사용한다.
@Configuration
@ComponentScan(basePackages = {"com.xxx.yyy.service", "com.xxx.yyy.repository"})
public class RootConfig {
@Autowired
private ApplicationContext applicationContext;
@Bean
public BasicDataSource dataSource() {
BasicDataSource basicDataSource = new BasicDataSource();
basicDataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver");
basicDataSource.setUrl("jdbc:oracle:thin:@localhost:1521:orcl");
basicDataSource.setUsername("name");
basicDataSource.setPassword("password");
return basicDataSource;
}
@Bean
public SqlSessionTemplate sqlSession() throws Exception {
return new SqlSessionTemplate((SqlSessionFactory) sqlSessionFactoryBean());
}
@Bean
public SqlSessionFactory sqlSessionFactoryBean() throws Exception {
SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
sqlSessionFactory.setConfigLocation(applicationContext.getResource("classpath:/mybatis-config.xml"));
sqlSessionFactory.setDataSource(dataSource());
return (SqlSessionFactory)sqlSessionFactory.getObject();
}
@Bean
public DataSourceTransactionManager transactionManager() {
DataSourceTransactionManager transaction = new DataSourceTransactionManager();
transaction.setDataSource(dataSource());
return transaction;
}
}
1) 컴포넌트 스캔
컴포넌트 스캔을 시작할 패키지를 명시해준다.
@Configuration
@ComponentScan(basePackages = {"com.xxx.yyy.service", "com.xxx.yyy.repository"})
public class RootConfig {
2) ApplicationContext
클래스경로에서 리소스를 가져오는 데에 사용되는 ApplicationContext 빈을 의존성주입 한다.
@Autowired
private ApplicationContext applicationContext;
3) 데이터베이스 연결
BasicDataSource
데이터베이스 연결을 위한 BasicDataSource 빈을 생성하고 드라이버 클래스 이름, URL, 사용자 이름, 암호 등 속성을 설정하는 부분이다.
어노테이션을 통해 생성하며 속성 설정은 xml 방식과 구조적으로 동일하다.
@Bean
public BasicDataSource dataSource() {
BasicDataSource basicDataSource = new BasicDataSource();
basicDataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver");
basicDataSource.setUrl("jdbc:oracle:thin:@localhost:1521:orcl");
basicDataSource.setUsername("name");
basicDataSource.setPassword("password");
return basicDataSource;
}
SqlSessionTemplate
MyBatis SQL 세션을 관리하는 데에 사용되는 SqlSessionTemplate, SqlSessionFactory 빈을 등록한다.
@Bean
public SqlSessionTemplate sqlSession() throws Exception {
return new SqlSessionTemplate((SqlSessionFactory) sqlSessionFactoryBean());
}
@Bean
public SqlSessionFactory sqlSessionFactoryBean() throws Exception {
SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
sqlSessionFactory.setConfigLocation(applicationContext.getResource("classpath:/mybatis-config.xml"));
sqlSessionFactory.setDataSource(dataSource());
return (SqlSessionFactory)sqlSessionFactory.getObject();
}
DataSourceTransactionManager
트랜잭션 관리를 위한 DataSourceTransactionManager 빈을 등록한다.
@Bean
public DataSourceTransactionManager transactionManager() {
DataSourceTransactionManager transaction = new DataSourceTransactionManager();
transaction.setDataSource(dataSource());
return transaction;
}
📁 Servlet-context.xml
기존의 Servlet-context.xml을 대체하기 위한 ServletContext 클래스를 생성한다.
WebMvcConfigurer 인터페이스를 상속하고, @EnableWebMvc 어노테이션을 붙여 스프링이 제공하는 웹 관련 빈을 자동으로 등록한다.
@EnableWebMvc
@ComponentScan(basePackages = {"com.sz.reminiscene.controller"})
public class ServletContext implements WebMvcConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
registry.viewResolver(viewResolver);
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
}
1) 컴포넌트 스캔
컴포넌트 스캔을 시작할 패키지를 명시해준다.
<context:component-scan base-package="com.XXX.YYY" />
@ComponentScan(basePackages = {"com.sz.reminiscene.controller"})
public class ServletContext implements WebMvcConfigurer {
2) View Resolver
응답 페이지와 관련한 뷰 리졸버를 설정하는 부분이다.
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
configureViewResolvers()
InternalResourceViewResolver 인스턴스를 생성하고 prefix, suffix를 설정한다.
속성 설정을 마친 뷰 리졸버 객체는 ViewResolverRegistry에 등록한다.
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
registry.viewResolver(viewResolver);
}
3) 정적 리소스 설정
이미지, 스타일시트, js파일 등 정적 리소스들의 정보를 기술하는 부분이다.
<resources mapping="/resources/**" location="/resources/" />
addResourceHandlers()
ResourceHandlerRegistry에 핸들러와 경로를 지정해준다.
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}