Spring MVC에서 xml환경에서 bean scan 방법

들어가기

자꾸 까먹는 부분이다. 특히 Junit 테스트 돌릴 때 이 bean scan을 잘 몰라서 해맨적이 있었다.

스프링 MVC에는 크게 root-context.xml 과 servet-context.xml로 나뉜다. 둘다 스프링 컨테이너를 위한 설정파일이다.

root-context.xml는 WEB과는 관련이 없는 설정을 담당하며, servet-context.xml는 WEB에 관련된 설정을 담당한다.

root-context.xml의 bean scan 설정

아래는 내 샘플 프로젝트의 root-context.xml이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">

<!-- Root Context: defines shared resources visible to all other web components -->

<!-- <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mokaboard_dev?useSSL=false"></property>
<property name="username" value="mokaboard"></property>
<property name="password" value="password"></property>
</bean> -->

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy"></property>
<property name="url" value="jdbc:log4jdbc:mysql://127.0.0.1:3306/mokaboard_dev?useSSL=false"></property>
<property name="username" value="mokaboard"></property>
<property name="password" value="password"></property>
</bean>

<!-- <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="classpath:/mybatis-config.xml"></property>
<property name="mapperLocations" value="classpath:mappers/**/*.xml"></property> MyBatis mapper 경로 지정한다.
</bean> -->

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="classpath:/mybatis-config.xml"></property>
<property name="mapperLocations">
<array>
<value>classpath:mappers/**/*.xml</value>
<value>classpath:sampleMappers/**/*.xml</value>
</array>
</property>
</bean>

<!-- SqlSessionTemplate은 MyBatis의 SqlSession인터페이스를 구현한 클래스로 기본적인 트랜잭션의 관리나 쓰레드 처리의 안정성 등을 보장해주고, 데이터베이스의 연겨로가 종료를 책임진다. -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate" destroy-method="clearCache">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"></constructor-arg>
</bean>

<context:component-scan base-package="com.hanumoka.mokaboard, com.hanumoka.sample" >
<!-- <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice" /> -->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

</beans>

bean scan 부분은 아래와 같다.

1
2
3
<context:component-scan base-package="com.hanumoka.mokaboard, com.hanumoka.sample" >
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

base-package를 보면 두개의 패키지의 bean들을 스캔한다. exclude-filter 를 이용하여 org.springframework.stereotype.Controller 즉 @Controller 빈들을 제외한 bean만 스캔한다.

servlet-context.xml의 bean scan 설정

아래 역시 내 샘플 프로젝트의 servlet-context.xml 파일 전체이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans
xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

<!-- DispatcherServlet Context: defines this servlet's request-processing
infrastructure -->

<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />

<!-- Handles HTTP GET requests for /resources/** by efficiently serving
up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />

<!-- Resolves views selected for rendering by @Controllers to .jsp resources
in the /WEB-INF/views directory -->
<!-- <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> -->

<!-- thymeleaf View 설정 -->
<beans:bean id="templateResolver" class="org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".html" />
<beans:property name="templateMode" value="HTML" />
<beans:property name="characterEncoding" value="UTF-8" />
<beans:property name="cacheable" value="false" />
</beans:bean>


<!-- thymeleaf laytout을 쓰기위해 3rd Party 추가 -->
<beans:bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine">
<beans:property name="templateResolver" ref="templateResolver" />
<beans:property name="additionalDialects">
<beans:set>
<beans:bean class="nz.net.ultraq.thymeleaf.LayoutDialect" />
</beans:set>
</beans:property>
</beans:bean>


<!-- thymeleaf laytout ViewResolver 설정 -->
<beans:bean
class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
<beans:property name="templateEngine" ref="templateEngine" />
<beans:property name="characterEncoding" value="UTF-8" />
<beans:property name="order" value="1" />
</beans:bean>

<context:component-scan base-package="com.hanumoka.mokaboard, com.hanumoka.sample" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<!-- <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice" /> -->
</context:component-scan>


</beans:beans>

baen scan 설정부분을 추려보면 아래와 같다.

1
2
3
<context:component-scan base-package="com.hanumoka.mokaboard, com.hanumoka.sample" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

root-context.xml와 같이 두개의 패키지를 스캔한다. use-default-filters="false" 의 의미는 component-scan의 기본 필터를 사용하지 않겠다는 의미이다. 기본필터는 @Component, @Repository, @Service, @Controller 어노테이션이 붙은 클래스들을 자동 탐지한다.

그리고 include-filter를 통해서 @Controller 가 지정된 빈만 스캔하게 설정한다.