프론트 엔드 컨트롤러는 전체 MVC 프레임 워크의 가장 핵심 부분입니다. 주로 요구 사항을 충족하는 외부 요청을 가로 채고 요청을 다른 컨트롤러에 배포하는 데 사용됩니다. 컨트롤러 처리 결과에 따르면 해당 응답을 생성하여 클라이언트로 보냅니다. 프론트 엔드 컨트롤러는 필터 (Struts2 가이 방법을 사용) 또는 서블릿 (스프링 MVC 프레임 워크)을 사용하여 구현할 수 있습니다.
사전 컨트롤러로서 Dispatcherservlet은 웹 서버의 입구이며 가장 중요한 스프링 MVC 클래스입니다. 수명주기를 통해 웹 서버에 대한 이해가 심화 될 수 있습니다.
서블릿의 수명주기
먼저 서블릿의 수명주기를 기억하겠습니다.
서블릿 라이프 사이클은 세 단계로 나뉩니다. [서블릿 라이프 사이클 및 작업 원리에 대한 자세한 설명]
1. init () 메소드는 초기화 단계에서 init ()이라고합니다. 서블릿이로드되면 서블릿 컨테이너는 서블릿 인스턴스를 생성하고 초기화를 위해 서블릿의 init () 메소드를 호출합니다. init () 메소드는 서블릿의 전체 수명 동안 한 번만 호출됩니다.
2. 클라이언트 요청 단계에 응답하여 서비스 () 메소드를 호출합니다.
3. 종료 단계에서 Destroy () 메소드를 호출하십시오
서블릿 초기화 단계
다음 순간에 서블릿 컨테이너가 서블릿을로드합니다.
1. 서블릿 컨테이너가 시작되면 일부 서블릿이 자동으로로드됩니다. 이를 구현하려면 web.xml 파일에서 <servlet> </servlet> 사이에 다음 코드 만 추가하면됩니다.
<loadon-startup> 1 </loadon-startup>
2. 서블릿 컨테이너가 시작된 후 클라이언트는 처음으로 서블릿에 요청을 보냅니다.
3. 서블릿 클래스 파일이 업데이트 된 후 서블릿을 다시로드하십시오.
Dispatcherservlet의 구조
위의 지식을 검토 한 후 Dispatcherservlet의 구조를 살펴 보겠습니다.
DispatcherServlet은 추상 클래스에서 상속됩니다 : 프레임 워크 스서스트 (Frameworkservlet), 간접적으로 httpservlet (httpservletbean의 Frameworkservlet 및 httpservletbean은 httpservlet의 상속)를 상속합니다.
서블릿 초기화
보호 된 void initStrateing (ApplicationContext Context) {initmultipartresolver (컨텍스트); // 파일 업로드 및 구문 분석. 요청 유형이 멀티 파트 인 경우 파일 업로드 및 멀티 패트 레졸버를 통해 구문 분석하십시오. initlocaleresolver (컨텍스트); // 현지화 구문 분석 initthemeresolver (컨텍스트); // 테마 구문 분석 inithAndLerMappings (컨텍스트); // inithandlerAdapters (Context)에 요청을 프로세서에 매핑합니다. // 여러 유형의 프로세서 매핑 inithAndLereXceptionResolvers (컨텍스트); // handlerAdapter를 통해 여러 유형의 프로세서를 지원합니다. // 실행 중에 예외가 발생하면 handlerexceptionResolver가 initRequestToviewnametranslator (컨텍스트)를 구문 분석하기 위해 양도됩니다. // view 이름으로 직접 구문 분석 initViewResolvers (컨텍스트); // viewResolver를 통해 논리보기 이름을 initflashmapmanager (컨텍스트)를 구현하기 위해 논리보기 이름을 특정 뷰로 해결합니다. // 플래시 맵 관리자}요청 처리 방법 :
서블릿의 서비스 방법은 HTTP 요청을 처리합니다.
Frameworkservlet.java는 다음과 같이 서비스를 정의하고 서블릿을 파괴합니다.
/** * 패치 * 요청을 가로 채기 위해 부모 클래스 구현을 무시합니다. */ @override Protected Void Service (httpservletrequest 요청, httpservletResponse 응답) servleTeXception, ioException {string method = request.getMethod (); if (method.equalsignorecase (requestMethod.patch.name ())) {processRequest (요청, 응답); } else {super.Service (요청, 응답); }}우리는 7 가지 유형의 HTTP 요청 유형 (옵션)이 있으며 다음과 같이 정의됩니다.
public enum requestmethod {get, head, post, put, patch, delete, 옵션, 추적}} Frameworkservlet의 서비스 ()는 다른 요청을 처리합니다. 우리는 공통 게시물을 사용하여 다음을 설명합니다.
/*** 결과에 관계없이 이벤트를 게시 하고이 요청을 처리합니다. * <p> 실제 이벤트 처리는 Abstract * {@link #doservice} 템플릿 메소드에 의해 수행됩니다. */ 보호 된 최종 무효 프로세스 레퍼링 (httpservletRequest 요청, httpservletResponse 응답)은 servleTexception, ioException {long starttime = system.currentTimEmillis (); 던질 수있는 failurecause = null; LocalEconText previouseLocalEconText = localEcontexTholder.getLocaleContext (); LocalEcontext localeContext = buildLocaleContext (요청); requestAttRibutes preverienattributes = requestContexTholder.getRequestAttributes (); servletrequestattributes requestAttributes = buildRequestAttributes (요청, 응답, previousAttributes); webasyncmanager asyncmanager = webasyncutils.getasyncmanager (요청); asyncmanager.registerCallableInterceptor (FrameworkServlet.class.getName (), 새 RequestBindingInterceptor ()); initContexTholders (요청, LocalEcontext, requestAttributes); try {doservice (요청, 응답); } catch (servletexception ex) {failurecause = ex; ex 던지기; } catch (ioexception ex) {failurecause = ex; ex 던지기; } catch (Throwable ex) {failurecause = ex; 새로운 NestedServleTexception을 던지십시오 ( "요청 처리 실패", 예); } 마침내 {resetContexTholders (요청, previousLocaleContext, previousAttributes); if (requestAttributes! = null) {requestAttributes.requestCompleted (); } if (logger.isdebugenabled ()) {if (afforeurecause! = null) {this.logger.debug ( "완료 할 수 없음", failurecause); } else {if (asyncmanager.isconcurrenthAndlingStarted ()) {logger.debug ( "동시 처리를 위해 응답을 열어 두는"); } else {this.logger.debug ( "성공적으로 완료된 요청"); }}} publishRequestHandleDevent (요청, startTime, failureCause); }} FrameworkServlet은 처리 흐름을 추상적으로 정의하고이를 서브 클래스로 맡겨 메소드를 구현하고 특정 요청 처리를 완료합니다.
/** * 서브 클래스는 요청 처리 작업을 수행하기 위해이 메소드를 구현해야합니다. * <p> 계약은 본질적으로 httpservlet의 일반적으로 재정의 * {@code doget} 또는 {@code dopost} 메소드의 계약과 동일합니다. * <p>이 클래스는 호출을 가로 채어 예외 처리 및 * 이벤트 출판이 이루어 지도록합니다. * @Param 요청 현재 HTTP 요청 * @Param 응답 현재 HTTP 응답 * @Throws 예외 모든 종류의 처리 실패의 경우 * @see javax.servlet.servlet.httpservlet#doget * @see javax.servlet.http.httpservlet */ protected void doid doserververved doserververververververt void doserververververeververt void doserververeverevert void doid doid doid doid httpservletresponse 응답) 예외를 던집니다.특정 구현은 다음과 같습니다.
/** * DispatcherServlet-Specific Request 속성을 노출시키고 실제 발송에 대해 {@link #dodispatch} *에 대의원을 노출시킵니다. */ @Override Protected Void Doservice (httpservletRequest 요청, httpservletResponse 응답)는 예외를 던졌습니다 {if (logger.isdebugenabled ()) {string resumed = webasyncutils.getAsyncManager (request) .hasconCurresult ()? "재개": ""; logger.debug ( "이름이있는 DispatcherErvlet (dispatcherservlet)" + getServletName () + " '" + " +" + "processing" + request.getMethod () + "[" + getRequesturi (request) + "]"); } // include의 경우 요청 속성의 스냅 샷을 포함하여 // 포함 후 원래 속성을 복원 할 수 있습니다. map <string, object> AqubutionSnapShot = null; if (webutils.isincludeRequest (request)) {AqubilitessNapShot = new Hashmap <String, Object> (); 열거 <?> attrnames = request.getAttributeNames (); while (attrnames.hasmoreElements ()) {String attrname = (string) attrnames.nextElement (); if (this.cleanupfterinclude || attrname.startswith ( "org.springframework.web.servlet") {aftributessnapshot.put (attrname, request.getAttribute (attrname)); }}}} // 핸들러와 객체를보기에 프레임 워크 개체를 사용할 수 있습니다. request.setattribute (web_application_context_attribute, getWebApplicationContext ()); request.setattribute (locale_resolver_attribute, this.localeresolver); request.setAttribute (테마_resolver_attribute, this.themeresolver); request.setAttRibute (테마_source_attribute, getTheMesource ()); FlashMap InputFlashMap = this.FlashMapManager.RETRIEVEANDUPDATE (요청, 응답); if (inputflashmap! = null) {request.setattribute (input_flash_map_attribute, collections.unmodifiablemap (inputflashmap)); } request.setAttribute (output_flash_map_attribute, new FlashMap ()); request.setattribute (flash_map_manager_attribute, this.flashmapmanager); try {dodispatch (요청, 응답); } 마침내 {if (webasyncutils.getAsyncManager (request) .IsconcurrenthAndlingStarted ()) {return; } // include의 경우 원래 속성 스냅 샷을 복원합니다. if (AqubireSsNapShot! = null) {retoreattributesafterInclude (request, autributessnapShot); }}}요청 분배기의 구현으로서 하이라이트 :
함수 : 1. 핸들러에 요청을 배포합니다 (구성 순서로 서블릿 매핑 관계를 얻음); 2. 쿼리 쿼리 서플릿에서 설치 한 핸들러 라디퍼를 기반으로 처리 할 수있는 첫 핸들러; 3. 핸들러는 요청을 처리합니다
/*** 핸들러로 실제 파견을 처리하십시오. * <p> 핸들러는 서블릿의 핸드 맵핑을 순서대로 적용하여 얻습니다. * 핸들러 클래스를 지원하는 첫 번째를 찾으려면 핸들러 라디 감자가 서블릿의 설치된 핸들러 라디 감체 *를 쿼리하여 얻습니다. * <p> 모든 HTTP 방법은이 방법에 의해 처리됩니다. 허용 가능한 메소드를 결정하는 것은 핸들러 라디퍼 나 핸들러 * 자체에 달려 있습니다. * @Param 요청 현재 HTTP 요청 * @Param 응답 현재 HTTP 응답 * @Throws 예외 모든 종류의 처리 실패의 경우 */ Protected void dodispatch (httpservletrequest 요청, httpservletreponse 응답) 예외 {httpservletrequest processedRequest = request; handlerexecutionchain mappedhandler = null; 부울 multipartrequestparsed = false; webasyncmanager asyncmanager = webasyncutils.getasyncmanager (요청); try {modelandview mv = null; 예외 DispatchException = null; try {processedRequest = Checkmultipart (요청); multipartrequestparsed = (ProcessedRequest! = request); // 현재 요청에 대한 핸들러를 결정합니다. 매핑 핸들러 = gethandler (ProcessEdRequest); if (mappedHandler == null || mappedHandler.gethandler () == null) {noHandlerFound (ProcessEdRequest, Response); 반품; } // 현재 요청에 대한 핸들러 어댑터를 결정합니다. handleradapter ha = gethandleradapter (mappedhandler.gethandler ()); // 핸들러에서 지원하는 경우 마지막으로 변형 된 헤더를 처리합니다. 문자열 메소드 = request.getMethod (); 부울 isget = "get".equals (메소드); if (isget || "head".equals (method)) {long lastmodified = ha.getLastModified (request, mappedHandler.gethandler ()); if (logger.isdebugenabled ()) {logger.debug ( "[" + getRequesturi (request) + "]는" + last-modified); } if (new servletwebrequest (요청, 응답) .CheckNotModified (lastModified) && isget) {return; }} if (new servletwebrequest (요청, 응답) .CheckNotModified (lastModified) && isget) {return; }} if (! mappedHandler.AppLyPreHandle (ProcessEdRequest, Response)) {return; } try {// 실제로 핸들러를 호출합니다. MV = HA.HANDLE (ProcessEdRequest, Response, MappedHandler.gethandler ()); } 마침내 {if (asyncmanager.isconcurrenthAndlingStarted ()) {return; }} applyDefaultViewName (요청, MV); MappedHandler.applyposthandle (ProcessEdRequest, Response, MV); } catch (예외) {dispatchException = ex; } ProcessDisPatchResult (ProcessEdRequest, 응답, MappedHandler, MV, DispatchException); } catch (예외) {triggerAfterCompletion (ProcessEdRequest, Response, MappedHandler, ex); } catch (Error err) {triggerFterCompletionWithError (ProcessEdRequest, 응답, 매핑 핸들러, err); } 마지막으로 {if (asyncmanager.isconcurrenthAndlingStarted ()) {// posthandle 및 completion mappedhandler.applyAfterConcurrenthAndlingStarted (ProcessEdRequest, Response); 반품; } // Multipart 요청에서 사용하는 모든 리소스를 정리하십시오. if (multipartrequestparsed) {cleanupmultipart (ProcessedRequest); }}}서블릿 파괴
/***이 서블릿의 webApplicationContext를 닫습니다. * @see org.springframework.context.configurableApplicationcontext#close () */ @override public void destrove () {getServletContext (). log ( "스프링 프레임 워크 스서비 레트 '" + getServletName () + ""); // 로컬로 관리되는 경우 webApplicationContext에서 close () 만 호출합니다 ... if (this.WebApplicationContext instancestof configurablePollectionContext &&! this.WebApplicationContextInjected) {((configurableApplicationContext) this.webapplicationContext); }}요약:
이 장의 한계로 인해이 기사는 요청 처리 프로세스 만 소개하며 코드의 심층 분석을 수행하지 않습니다. 다음 기사는 세부 사항에서 시작하여 Spring 코드의 아름다움을 분석합니다.
위는이 기사의 모든 내용입니다. 모든 사람의 학습에 도움이되기를 바랍니다. 모든 사람이 wulin.com을 더 지원하기를 바랍니다.