Back-end/JAVA,Spring

[Spring]Application Context 설정.

cheersHena 2018. 11. 7. 18:36
반응형

Spring Framework 설정.


1.  Root Application Context 설정 [web.xml]

Servlet Container인 Tomcat(WAS)이 start되면 가장먼저, web.xml을 읽어들인다.

[web.xml] = Root

<!--Root Application Context-->
<listener>
<listener-class> org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation </param-name>
<param-value>classpath*:/root-context*.xml</param-value>
</context-param>

[web.xml]에 선언된 listener클래스인 ContextLoaderListener 의해 RootWebApplicationContext영역을 구성하게 되는데 그 설정파일은 root-context*.xml이다.


[root-context.xml]

<import resource="database/Spring-Datasource.xml"/>
<import resource="beans/Spring-Beans.xml"/>

두파일을 import 하고있다.


[Spring-Datasource.xml]

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/[DB NAME]?serverTimezone=UTC&amp;characterEncoding=UTF-8" />
<property name="username" value="[userID]"/>
<property name="password" value="[password]"/>
</bean>

JDBC 프로그래밍에서는 데이터베이스 연결위해 클래스(객체)생성하고 객체간 관계(의존관계)를 생각해 import하여 모든 작업을 개발자가 직접했는데 이 작업을 개발자에게서 분리하고, Spring이 대신 할 수 있도록 Spring Bean(IoC)을 선언한다. 

위 파일처럼 Spring-beans.xml 파일도 읽어와 프로젝트에 필요한 빈을 선언하고, 생성할 준비를 한다. 이는 모두 Spring-Container의 역할이고, 개발자는 Spring Bean의 선언/생성에 관여 할 수 없다. 


2. Servlet설정: Child Web Application Context 설정 

서블릿 환경의 비효율적인 부분 해결하기 위해 Spring의 Dispatcher Servlet을 선언하여, 

Spring이 대신할 수 있도록 한다. 

<!--Spring Servlet Start -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframeowork.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<!--Spring Servlet End -->

사용자가 요청한 URL이 [.do]로 끝나게 되면 이 요청을 Spring의 DispatcherServlet이 대신하게끔 설정했고, 이에 대한 세부적 설정이 필요하다. 이 설정파일의 파일명은 servlet-name값이 포함된 이름이어야 한다. 경로는 web.xml과 같은 위치인 /WEB-INF/이다.

ex)

 Servlet Name 

 File Name

 dispatcher

 dispatcher-servlet.xml 

 spring-web 

 spring-web-servlet.xml 

 web

 web-servlet.xml 

[servlet.xml]은 사용자 요청을 받아들이는 것에 관련된 설정을 하게되는데 Controller영역이라고 생각하면 된다.  때문에 실제로 요청을 처리할 Controller에 대한 Bean설정을 이 servlet.xml에 하게된다.    [ 요청 -> Servlet -> Controller ]


** 정리 

독립 웹 모듈로 만들어진 스프링 어플리케이션에 application context는 2개가 들어간다.
1) <ContextLoaderListener>에 의해서 만들어지는 Root WebApplicationContext
2) <DispatcherServlet>에 의해서 만들어지는 WebApplicationContext이다.

1. Root WebApplicationContext ( Root영역 )

이름 그대로 최상단에 위치한 Context로 
1)서비스 계층이나 DAO를 포함한, 웹 환경에 독립적인 빈들을 담아둔다.
2)서로 다른 서블릿컨텍스트에서 공유해야 하는 빈들을 등록해놓고 사용할 수 있다.
3)Servlet context에 등록된 빈들 이용 불가/servlet context와 공통된 빈이 있다면 servlet context 빈이 우선된다.
4)WebApplication 전역에 사용가능한 DB연결, 로깅 기능들이 이용된다.

2. WebApplicationContext (Child 영역 )

서블릿에서만 이용되는 Context로
1)DispatcherServlet이 직접 사용하는 컨트롤러를 포함한 웹 관련 빈을 등록하는 데 사용한다.
2)DispatcherServlet은 독자적인 WebApplicationContext(like 지역변수) 를 가지고 있고, 모두 동일한 Root WebApplicationContext(like 전역변수)를 공유한다.



Spring Bean의 명시적 선언 - 수동 DI

개발자가 빈을 명시적으로 선언하여 객채 생성의 책임을 스프링으로 넘길 수 있다.

[Spring-beans.xml]

<bean id = "fUtil" class="com.util.FileUtil">
<property name="location" value="/home/ubuntu/app/upload"/>
</bean>

위 코드처럼 빈을 선언할 수 있고 개발자가 접근하고자 한다면 id인 fUtil로 접근할 수 있다. 선언하는 빈에서 기능을 수행하기 위해 어떠한 값(value)을 외부에서 입력해야 한다면 property로 전달할 수 있다. 

[property와 대응되는 set메서드]

public void setLocation(String location){
this.saveLocation = location;
}

외부에서 전달한 값을 내부에서 사용 할 수 있도록 멤버 변수가 있어야 한다.

이때, property name에 적인 값이 setter메서드 이름이 된다. location -> setLocation

* 수동 DI에서 필요한것: setter메소드, 멤버변수(객체)

(파라미터값을 내부해서 사용할수 있도록)  


Spring Bean의 묵시적 선언 - 자동 DI

과거 2.x 버전에서는 개발자가 프로그램에 필요한 Spring Bean을 설정 파일에 모두 명시해주었다. 시간이 흘러 시스템이 점점 커지고 이에 비례하여 개발자가 명시해주는 빈이 점점 많아지는 불편함이 생겼고 이를 해결하고자 3.x이후 버전에서는  어노테이션을 활용하여 묵시적으로 선언한다. 

선언하고자 하는 객체 성격따라 어노테이션이 달라진다.

 객체의 성격

 어노테이션 @  

 Controller

 @Controller 

 Service

 @Service 

 DAO

 @Repository 

 그 외 Utility 성격 

 @Component 

이 어노테이션을 class선언부 앞에 명시해 주면 된다. 

@Controller
public class NoticeController{


어노테이션 사용하여 빈설정을 자동화 하였지만 이는 선언 코드일뿐, 스프링 컨테이너가 찾지 못하면 빈을 선언할 수 없고 생성할 수 없다. 따라서 어노테이션을 찾을 수 있도록 객체성격에 따른 영역에 설정에 별도설정이 필요하다.

 객체 성격

 어노테이션 

 설정 영역 

 Controller

 @Controller 

 Child Application(Servlet)  

 Service

 @Service 

 Root Application 

 Dao

 @Repository

 Root Application 

 그 외 Utility성격 

 @Component

 Root 또는 Child application

*어노테이션 설정을 해도 찾아주지 않으면 절대 Bean이 생성되지 않는다.



Spring Bean 선언/ 생성 위한 탐색(Scan)

Spring container가 찾을 수 있도록 아래 코드처럼 설정을 해주어야 한다.

[servlet.xml] = Child Application영역 - controller

<context:component-scan base-package="com." use-default-filters="false">
<context:include-filter
type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

1) base-package 경로의 모든 클래스 읽어들임. (여기선 com. 이하 경로) 

2)context:include-filter   에 적용한 어노테이션이 존재하면. (여기선 @Controller)


[Spring-beans.xml] = Root Application영역 - Service, Dao

<context:component-scan base-package="com.">
<context:include-filter
type="annotation"
expression="org.springframework.stereotype.Service"/>
<context:include-filter
type="regex" expression="\.*\.dao\.*"/>
</context:component-scan>

1) base-package 경로의 모든 클래스 읽어들임. (여기선 com. 이하 경로) 

2)context:include-filter type="annotation

: 에 적용한 어노테이션(@만 찾음.)이 존재하면. (여기선 @Service) 

   context:include-filter type="regex" (정규식)

: 설정해놓은 위치에 존재하면. 

--> 찾고자 하는 어노테이션으로 탐색할 수 있고, 정규식(regex)이용해 탐색할 수 있다. 

중요한 것은 각 영역에 맞추어 설정 해 주어야 한다! 







반응형