BackEnd/Spring

SpringMVC_DB_국비Day84

Leo.K 2022. 6. 30. 14:44

[ Spring MyBatis환경설정 ] ★

spring이 contextLoaderListener객체를 생성하면, contextLoaderListener이 객체가 ds, factoryBean, sqlSession 빈을 생성하고 의존성 주입까지 해준다.

1. src/main/resources 폴더에 config.spring.context 패키지를 추가한다. 

spring에서  DB를 사용하기 위해서는 DI를 위해 여러가지 환경설정 xml파일이 필요하다. 이를 하나의 root-context.xml 파일에 모든 DB 환경설정 정보를 만들면 후에 일일히 찾아서 유지보수가 어렵기 때문에 따로 패키지를 만들어서 분류한다. 물론 새로운 환경 설정을 만들것이기 때문에 root-context.xml파일은 삭제할 것이다. src/main/java와 src/main/resources폴더에 있는 내용은 실행시에 편집경로가 아닌 실행 파일 경로인 classes파일에 들어가는데 이 폴더의 경로가 classpath이다. 

2. 다음 4개의 파일을 config.spring.context패키지 아래 생성한다. 이 패키지에는 초기에 생성되어 DI되는 라이브러리에 대한 환경설정이 생성된다.

  • context-1-datasource.xml
  • context-2-mybatis.xml
  • context-3-dao.xml
  • context-4-service.xml

3. 프로젝트가 실행되면 web.xml파일을 먼저 읽어서 필요한 파일을 생성한다고 했다. 하지만 이는 기존에 root-context파일을 참고하여 초기화하도록 기본 설정이 되어있는데 우리는 지금 환경설정 파일의 위치를 바꾸었기 때문에 그 경로를 바꾸어 수정해주어야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- 변경 전 -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
 
<!-- 변경  -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <!-- 새로 생성되는 xml파일의 명명법만 일관되게 유지한다면 추가적인 xml파일이 발생해도 이 부분을 수정하지 않아도 된다. -->
    <param-value>classpath*:config/spring/context/context-*.xml</param-value>
</context-param>
 
cs

 

4. src/main/resources 폴더에 config.spring.servlet 패키지를 추가한다. 이 패키지에는 초기에 생성되는 서블릿에 대한 환경설정 파일이 저장된다. 위와 같은 방법으로 servlet-context.xml파일을 복사해서 이곳에 붙여넣고 기존의 파일을 삭제한다. 물론 그로 인해 경로를 바꾸어주어야 하는데 이 방식 또한 위와 같다.

1
2
3
4
5
6
7
8
9
10
11
12
<!---->
<init-param>
    <param-name>contextConfigLocation</param-name>
    <!-- 아래의 파일(servlet-context.xml)을 참고해서 초기화 한다. -->
    <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
 
<!--변경 후-->
<init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:config/spring/servlet/servlet-context.xml</param-value>
</init-param>
cs

 

5. 초기 환경설정 시 적용할 인코딩 필터를 추가한다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- 스프링에서 인코딩 설정하기. -->
<filter>
    <filter-name>characterEncodingFilter</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>characterEncodingFilter</filter-name>
    <url-pattern>*.do</url-pattern>
</filter-mapping>
cs

 

6.  src/main/resources폴더에 mybatis연결을 위한 환경설정 파일을 추가해야 한다. 

dp.properties를 jbdc.을 붙여서 다음과 같이 수정한다.

 

7. context-1-datasource.xml 파일에 dp.properties파일을 읽을 수 있도록 환경설정 내용을 추가한다.

하지만 추가만 하면 에러가 날텐데 이제부터 에러를 잡아줘야 한다. 

아래의 메뉴 중에서 namespaces를 클릭한다.

context를 체크하고 저장을 누른다. 

1
2
3
4
5
6
7
8
9
10
<context:property-placeholder 
    location="classpath:config/mybatis/db.properties"/>
 
<bean id="ds" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="${driver}"/>
    <property name="url" value="${url}"/>
    <property name="username" value="${username}"/>
    <property name="password" value="${password}"/>
    <property name="defaultAutoCommit" value="false"/>
</bean>
cs

 

마지막으로 라이브러리를 등록해주어야 한다.

아래의 이미지를 참고해서 라이브러리를 등록하도록 하자. 오타로 인한 에러를 방지하기 위한 방법이다. 

 

 

8. context-2-mybatis.xml 파일에 mybatis관련 환경설정 내용을 추가한다.

factoryBean을 보면 두 가지 속성이 주입되었는데, 이는 dbcp정보와 mapper정보를 가지고 있는것이다. 이는 mybatis를 처음 배울 때, sqlSessionFactory가 sqlMapConfig.xml파일을 참고해서 생성이 되는데, 이때 sqlMapConfig.xml에는 dbcp정보와 mapper정보를 가지고 있다. 이렇게 두 가지 정보를 참조해서 생성하는 과정이 같은 것이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
<bean id="factoryBean" 
        class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="ds" />
    <property name="configLocation" 
              value="classpath:config/mybatis/mybatis-config.xml"/>
</bean>
 
<!--  SqlSession sqlSession 생성 
      SqlSessionTemplate  template;
 -->    
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
    <constructor-arg ref="factoryBean" />
</bean>
cs

이제 jdbc드라이버를 찾아야 하는데, oracle과 maven의 라이선스 문제로 인해서 자주 주소가 바뀐다고 한다. maven의 중앙 repos에서 라이브러리를 다운받는 입장에서 계속 주소가 바뀌는 것은 불편하기 때문에 다른 방법을 사용한다. 결국에 이 드라이버를 사용하는 서버는 톰캣이기 때문에 톰캣이 설치된 경로의 lib폴더에 ojdbc14.jar파일을 복사해놓으면 된다.

마지막으로 mybatis만 의존성을 주입하면 된다. pom.xml에 아래의 코드를 작성한다.

 

여기까지 환경 설정을 진행했다면, 아래와 같은 bean graph가 생성될 것이다.

datasource 생성 -> ds주입 -> factory Bean생성 -> factory bean주입 -> sqlsession생성

 

[ Spring Interface기반 프로젝트 ]

앞으로는 인터페이스기반으로 프로그래밍을 하기 때문에, dao를 클래스가 아닌 인터페이스로 생성한다. vo는 기존에 하던 방식으로 클래스로 만든다.

DeptDaoImpl은 DeptDao인터페이스를 구현 상속하는 클래스이다. 가장 위의 이미지를 보면 DeptDao는 SqlSessionTemplate으로부터 의존성을 주입받는다. 즉, SqlSessionTemplate이 없으면 DeptDao를 사용할 수 없다는 것이다. 이때, SqlSessionTemplate은 SqlSession인터페이스를 구현 상속하는 클래스이다. 특정 기능을 사용하는 사용자에게는 설계서가 아닌 설명서를 주어야 한다. 이때, deptdao는 sqlsessiontemplate에게 의존성을 주입받는 즉, 사용자라는 것이다. 따라서 SqlSessionTemplate이 아니라 SqlSessionTemplate에게 상속을 하는 SqlSession을 주어야 하는 것이다.

 

 

 

 

[ Spring DB의 폴더구조 ]

 

[ 정리 ]

  1. 프로젝트를 실행하면 web.xml파일을 읽는다. 
  2. 스프링이 ContextLoaderListener객체를 만드는데, 생성한 ContextLoaderListener객체가 다음의 변경된 경로(classpath*:config/spring/context/context-*.xml)에 있는 환경설정 파일을 확인한다. 이 파일의 내용을 참조해서 파일 내부에 정의된 bean태그를 확인해서 해당하는 클래스를 생성한다. 
  3. 이때 생성 순서가 중요한데, DB부터 차근차근 생성하고 다음으로 생성되는 클래스는 이전에 생성된 클래스에게 의존성을 주입받는다. 
  4. 가장 위의 이미지를 참고하면 ds는 factoryBean에게 의존성을 주입한다. 이 말을 직역하면, factoryBean이 ds를 의존한다는 뜻이며, 좀 더 쉽게 이야기 해보면, ds가 없으면 factoryBean은 의미가 없다는 뜻이 된다. 실제 모델 2구조를 학습할때 factory가 dbcp의 정보를 참고하지 않았는가? 이 말은 factory가 있기 위해서는 정보를 제공해주는 ds가 필요하다는 뜻이고 이를 factory가 ds를 의존한다고 하는 것이다. 그렇기 때문에 factoryBean보다 ds가 먼저 생성되어야 하고, 생성 순서가 중요하다는 것이다. 
  5. 여기서 하나만 더 이야기 해보자. 쉽게 예시를 들면 인터페이스는 어떤 모듈의 기능을 사용하는 방법을 설명해주는 사용설명서(추상클래스 뿐)이고, 구현 클래스는 해당 설명서를 기반으로 자세한 기능을 구현한 설계서이다. 이때, 사용자에게 설계서를 줄 필요가 있을까? 아니다. 사용자에게는 설계서가 아닌 설명서를 주고 알아서 자유롭게 사용하도록 (다형성)하는 것이다. 따라서 주입이 모두 되었다고 했을때, 역으로 실행할 때는 주입 역순으로 실행이 되는데, 이때 의존성을 주입하는 ds는 factoryBean에게 설계서가 아닌 설명서 즉, 인터페이스를 제공한다. 
  6. 스프링이 직접 생성해주는 것은 설계서이지만 이 설계서에게 상속을 하는 설명서를 주는 것이다. 쉽게 말하면 이전에 자바에서 하던 업캐스팅 선언이라고 생각하면 되는 것이고, 이것이 인터페이스를 기반으로 프로젝트 하는 것이다. 
    1. classpath:config/spring/context/context-1-datasource.xml파일을 읽어서 dbcp를 사용하기 위해서 BasicDataSource를 생성한다. 
    2. classpath:config/spring/context/context-2-mybatis.xml파일을 읽어서 factoryBean을 생성하고, SqlSessionTemplate을 생성한다. 
      1. factoryBean을 생성하는데 이는 ds로 부터 dbcp정보를 DataSource라는 인터페이스로 setter 주입 받고, mapper정보를 다른 xml파일로부터 주입받아서 생성된다. 
      2. factoryBean에게 생성자 주입을 받아서 SqlSessionTemplate이 생성된다.
    3. classpath:config/spring/context/context-3-dao.xml파일을 읽어서 DeptDaoImpl을 생성한다.
      1. SqlSessionTemplate의 인터페이스인 SqlSession을 생성자를 통해 생성자 주입받는다. 
    4. 마지막으로 DispatcherServlet이 servlet-context.xml파일을 읽어서 DeptController를 생성하는데, 앞서 생성한 DeptDaoImpl의 인터페이스 DeptDao을 생성자를 통해 생성자 주입받는다. 

계속해서 인터페이스를 준다고 했는데, 이를 너무 헷갈리게 생각하지 말자. 인터페이스를 줌으로써 나를 의존하는 클래스에게 나를 사용하는 방법을 알려주었을 뿐이다. 가장 중요한 것은 의존성이 주입된 모든 클래스가 의존관계인 것이 아니라 인접한 두 클래스 끼리만 독립적인 의존관계를 가진다는 것을 인지하면 헷갈리지 않을 것이다.

'BackEnd > Spring' 카테고리의 다른 글

Spring_국비_Day86  (0) 2022.07.05
SpringFileUpload_국비_Day86  (0) 2022.07.04
SpringMVC_Parameter_국비_Day83  (0) 2022.06.29
SpringCollection_국비Day82  (0) 2022.06.28
Spring학습_Day4_AOP  (0) 2022.06.28