1. Tomcat에 의해 web.xml 로드하고, web.xml의 ContextLoaderListener 생성
* ContextLoaderListener
- ServletContextListener 인터페이스를 구현하고 있으며, ApplicationContext를 생성하는 역할을 수행한다.
- Servlet의 생명주기를 관리해준다.
- Servlet을 사용하는 시점에 서블릿 컨텍스트에 ApplicationContext 등록, Servlet이 종료되는 시점에 ApplicationContext 삭제
- `contextConfigLocation` 파라미터를 사용하여 load할 수 있는 설정파일을 지정
* ApplicationContext
- IoC엔진, bean의 생명주기 담당
- 최상위 컨텍스트
- root-context에 등록되는 빈들은 모든 컨텍스트에서 사용 할 수 있다. (공유가능)
- Service, DAO를 포함한 웹환경에서 독립적인 Bean들을 담아둔다. (@Service, @Repository)
- 서로 다른 servlet-context에서 공유해야 하는 빈들을 등록해놓고 사용할 수 있다.
- servlet-context내 Bean들은 이용이 불가능하다.
// web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<display-name>ㅇㅇㅇㅇ</display-name>
<description></description>
<context-param>
<param-name>package.version</param-name>
<param-value>5.3.5.0-SNAPSHOT</param-value>
</context-param>
<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>*.do</url-pattern>
<url-pattern>*.json</url-pattern>
</filter-mapping>
<filter>
<filter-name>HTMLTagFilter</filter-name>
<filter-class>softin.sams.framework.filter.HTMLTagFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HTMLTagFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
<filter>
<filter-name>FServiceLogFilter</filter-name>
<filter-class>softin.sams.framework.filter.FServiceLogFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>FServiceLogFilter</filter-name>
<url-pattern>*.do</url-pattern>
<url-pattern>*.json</url-pattern>
</filter-mapping>
<filter>
<filter-name>WebResourceAuthorizedFilter</filter-name>
<filter-class>softin.sams.framework.filter.WebResourceAuthorizedFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>WebResourceAuthorizedFilter</filter-name>
<url-pattern>/docs/*</url-pattern>
</filter-mapping>
<!-- <filter>
<filter-name>CustomWebSecurityFilter</filter-name>
<filter-class>softin.sams.framework.filter.CustomWebSecurityFilter</filter-class>
<init-param>
<param-name>content.security.policy</param-name>
<param-value>default-src 'self'; connect-src 'self' *.kakao.com; script-src 'self' 'unsafe-inline' 'unsafe-eval' *.kakao.com *.daumcdn.net; style-src 'self' 'unsafe-inline'; img-src 'self' data: *.kakao.com *.daumcdn.net;</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CustomWebSecurityFilter</filter-name>
<url-pattern>*.do</url-pattern>
<url-pattern>*.json</url-pattern>
</filter-mapping> -->
<!-- ② contextConfigLocation 파라미터를 사용하여 load할 수 있는 설정파일을 지정 ★★★ -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:inframework/spring/context-*.xml,
classpath*:inframework/spring/custom/context-*.xml
</param-value>
</context-param>
<!-- ① ContextLoaderListener ★★★ -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 서블릿 컨텍스트 파일 경로 지정 ★★★ -->
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/config/inframework/springmvc/dispatcher-*.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
<url-pattern>*.json</url-pattern>
<url-pattern>*.in</url-pattern>
</servlet-mapping>
<!-- <servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.html</url-pattern>
<url-pattern>*.css</url-pattern>
<url-pattern>*.js</url-pattern>
<url-pattern>*.jpg</url-pattern>
<url-pattern>*.png</url-pattern>
<url-pattern>*.gif</url-pattern>
</servlet-mapping> -->
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
<session-config>
<cookie-config>
<name>Softin-ORGN_SID</name>
</cookie-config>
<session-timeout>60</session-timeout>
<tracking-mode>COOKIE</tracking-mode>
</session-config>
<welcome-file-list>
<welcome-file>index.do</welcome-file>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<error-page>
<error-code>403</error-code>
<location>/html/errorView.html</location>
</error-page>
<error-page>
<location>/error/errorView.do</location>
</error-page>
<!-- JNDI 설정 -->
<resource-ref>
<description>JNDI DATASOURCE</description>
<res-ref-name>JNDI-softin-orgn</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
<!-- Security -->
<security-constraint>
<web-resource-collection>
<web-resource-name>Allowed methods</web-resource-name>
<url-pattern>/*</url-pattern>
<http-method-omission>GET</http-method-omission>
<http-method-omission>POST</http-method-omission>
</web-resource-collection>
<auth-constraint />
<!-- HTTPS Redirect -->
<!-- <user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint> -->
</security-constraint>
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<trim-directive-whitespaces>true</trim-directive-whitespaces>
</jsp-property-group>
</jsp-config>
</web-app>
2. contextConfigLocation에 mapping된 xml 파일을 기준으로 Spring Container(ROOT: 첫번째 spring container)가 구동
- 여기서 대상이 되는 xml파일은 case가 여러가지가 될수 있다. ( ex. root-context.xml, applicationContext.xml)
- 아래 예시의 경우 (context-common.xml) 전자정부 프레임워크의 context-*.xml 파일들에서 설정한 내용들을 모두 합쳐놓은 부분
- 여기서 대상이 되는 xml파일은 주로 view 지원을 제외한 공통 bean을 설정한다.(web과 관련된 bean들은 등록하지 않음)
// context-common.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- Component scan -->
<context:component-scan base-package="inframework,softin.sams">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- Spring XML 설정파일에서 Properties 정보 읽어 올수 있도록 추가 -->
<bean id="propertyConfigurer" class="softin.sams.framework.properties.configurer.EncryptablePropertyConfigurer">
<!-- SamsProperties 에서 properties 설정 파일 로드 처리함 -->
<property name="samsProperties" ref="samsProperties" />
</bean>
<!-- MessageSource -->
<bean id="localMessageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>classpath:/inframework/message/message-common</value>
<value>classpath:/inframework/message/message-code</value>
</list>
</property>
<property name="defaultEncoding" value="UTF-8"/>
<property name="cacheSeconds">
<value>60</value>
</property>
</bean>
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"/>
<!-- 로컬 리소스 -->
<bean id="samsMessage" class="softin.sams.framework.properties.SamsMessage">
<property name="messageSource" ref="localMessageSource" />
</bean>
<bean id="samsProperties" class="softin.sams.framework.properties.SamsProperties" init-method="loadProperties">
<property name="samsMessage" ref="samsMessage" />
</bean>
<!-- DB 리소스 -->
<bean id="messageSource" class="softin.sams.framework.properties.DBMessageSource">
</bean>
<bean id="samsDBMessage" class="softin.sams.framework.properties.SamsDBMessage">
<property name="messageSource" ref="messageSource" />
</bean>
<!-- MultiPart File Upload -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="${Globals.upload.maxUploadSize:10485760}"/>
<property name="maxInMemorySize" value="${Globals.upload.maxInMemorySize:10240}"/>
</bean>
</beans>
3. Client로부터 웹 어플리케이션 요청이 옴.
- 최초의 클라이언트 요청에 의해 DispatcherServlet 생성
- DispatcherServlet 객체는 WEB-INF/config 폴더에 존재하는 대상이 되는 xml파일 (ex. servlet-context.xml) 파일을 로딩하여 두번째 스프링 컨테이너를 구동
- 이 두 번째 스프링 컨테이너가 Controller 객체를 메모리에 생성한다.
- DispatcherServlet은 FrontController의 역할을 수행한다.(클라이언트로부터 요청 온 메시지를 분석하여 알맞은 PageController에게 전달하고 응답을 받아 요청에 따른 응답을 어떻게 할지 결정한다.)
- 이때 첫번째 Spring Container(ROOT) 가 구동되면서 생성된 DAO, VO, ServiceImpl 클래스들과 협업하여 알맞은 작업을 처리하게 된다.
* DispatcherServlet 클래스에 의해 만들어지는 것이 WebApplicationContext
* WebApplicationContext
- servlet-context에 등록되는 빈들은 해당 컨텍스트에서만 사용할 수 있다.
- DispatcherServlet이 직접 사용하는 Controller를 포함한 웹 관련 빈을 등록하는 데 사용 (@Controller)
- 독자적인 컨텍스트들을 가지며, root-context 내 빈 사용이 가능
// dispatcher-servlet.xml
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd" >
<!-- <context:component-scan base-package="inframework,softin">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan> -->
<!-- 패키지 내 Controller, Service, Repository 클래스의 auto detect를 위한 mvc 설정 -->
<context:component-scan base-package="inframework,softin.sams,softin.test" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--
<mvc:annotation-driven />
<context:annotation-config />
<aop:aspectj-autoproxy />
-->
<!-- <mvc:annotation-driven /> -->
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<!-- JSON HTML Tag escape 처리 -->
<!-- ★★★ HttpMessageConverter: 자바객체와 Http 요청/응답 몸체 사이의 변환 처리-->
<bean class="softin.sams.framework.common.gson.CustomGsonHttpMessageConverter" />
</mvc:message-converters>
</mvc:annotation-driven>
<aop:aspectj-autoproxy />
<!-- 인증 인터 셉터 -->
<mvc:interceptors>
<!-- 사용자 인증 사용하는 경우 아래 path 추가 필수 -->
<mvc:interceptor>
<mvc:mapping path="/cmm/**" />
<mvc:mapping path="/web/**" />
<mvc:mapping path="/api/**" />
<mvc:mapping path="/inorg/**" />
<!-- exclude -->
<mvc:exclude-mapping path="/api/msagw/**"/>
<mvc:exclude-mapping path="/msagw/api/**"/>
<bean class="softin.sams.framework.interceptor.DefaultAuthInterceptor" />
</mvc:interceptor>
<!-- 로그인 접근 인증 -->
<mvc:interceptor>
<mvc:mapping path="/login/**" />
<!-- exclude -->
<mvc:exclude-mapping path="/login/logout.do"/>
<bean class="softin.sams.framework.interceptor.LoginAccessInterceptor" />
</mvc:interceptor>
<!-- 서버 -->
<mvc:interceptor>
<mvc:mapping path="/server/**" />
<!-- health check -->
<mvc:exclude-mapping path="/server/health/**"/>
<bean class="softin.sams.framework.server.interceptor.ServerAuthenticInterceptor" />
</mvc:interceptor>
<!-- MSA GW -->
<mvc:interceptor>
<mvc:mapping path="/api/msagw/**" />
<mvc:mapping path="/msagw/api/**" />
<bean class="softin.sams.framework.msagw.interceptor.MsaGwAuthenticInterceptor" />
</mvc:interceptor>
<!-- Open API -->
<mvc:interceptor>
<mvc:mapping path="/openapi/**" />
<bean class="softin.sams.framework.openapi.interceptor.OpenApiServerInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
<!-- Tiles3 적용 -->
<bean id="tilesViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver" p:order="1">
<property name="viewClass" value="org.springframework.web.servlet.view.tiles3.TilesView" />
</bean>
<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/config/inframework/tiles/default-layout.xml</value>
</list>
</property>
</bean>
</beans>
4. 클라이언트 요청으로부터 DispatcherServlet의 전체 흐름
- 클라이언트가 해당 어플리케이션에 접근하면 접근한 URL 요청을 DispatcherServlet이 가로챔
- RequestMappingHandlerMapping이 해당 요청을 처리할 컨트롤러를 찾음
- DefaultListableBeanFactory 가 mainContoller 를 쓰면 된다고 알려줌
- RequestResponseBodyMethodProcessor가 servlet-context.xml 에 선언해놓은 MessageConverter을 이용하여 요청 바디(파라미터)를 읽음
- DataSourceTransactionManager 로 DB 접속
- 컨트롤러에서 view를 리턴하면 ViewResolver가 먼저 받아 해당 view가 존재하는지 검색
- DispatcherServlet은 ViewResolver를 통해 접두사와 접미사가 붙은 JSP 파일의 이름과 경로를 리턴받아 최종적으로 JSP를 실행. view에 결과를 보낸 후 DispatcherServlet은 최종 결과를 클라이언트에 전송
'Framework' 카테고리의 다른 글
[Spring] 스프링의 4가지 concept 정리 (0) | 2023.06.02 |
---|---|
개발표준 (0) | 2023.04.27 |
[Spring] PostConstruct (0) | 2023.04.04 |
Front-End Framework 정리 (0) | 2021.06.13 |
스프링(Spring) AOP : AspectJ Pointcut 표현식 (Feat. 프로젝트에서 꼭 활용할 내용들) (0) | 2020.03.31 |