기본 아키텍처
Tomcat
그것은 두 개의 모듈 공동으로 구성
connector
container
connector
구문 분석에 대한 책임 HTTP
, 예를 들어, 요청을 请求头
, 查询字符串
, 등이있다. 세대 와 나중에 넘겨 적절한를 호출 할 책임이있다, .请求参数
HttpRequest
HttpResponse
container
Servlet
커넥터
Tomcat
기본값은 Connector
입니다 HttpConnector
. 마찬가지로 Connector
우리가 구현해야하는 Connector
이 인터페이스를.
Tomcat
그것은 나중에 열려면 시작 스레드 에 의해 무한 루프를 수행 ServerSocket
요청을 기다리고. 요청이 생성되면 Socket
,이 점에 유의 HttpConnector
자신을 처리하지 않습니다 Socket
,하지만 그것을 줄 HttpProcessor
. 자세한 사항은 아래를 참조 코드 여기 난 단지 키 코드를 유지.
공공 무효 실행 () { 우리가 shutdown 명령을받을 때까지 // 루프 {(! 정지) 동안 소켓 소켓 = NULL을; {시도 ) (소켓 = serverSocket.accept을; //等待链接 } 캐치 (AccessControlException가 에이스) { ( "소켓 보안 예외를 허용"에이스) 로그; 잇다; } // 적절한 핸드 오프 프로세서 소켓 HttpProcessor 프로세서 createProcessor = (); processor.assign (소켓); //这里是立刻返回的 가 완료되면, 프로세서는 그 자체를 재활용한다 // } }
위의가 있습니다 processor.assign(socket);
즉시 반환해야하며, 대기가 차단되지 않습니다. Tomcat이 하나 개의 요청을 처리 할 수 없기 때문에, 각, 비동기 processor
프로세스는 별도의 스레드입니다.
HttpProcessor
위의 코드는 쇼 호출하지 않습니다 이 방법은 그것을 호출하는 방법이다, 방법은? 이제 살펴 보자 방법.HttpProcessor
process
HttpProcessor
run
공공 무효 실행 () { // 우리가 종료 신호를받을 때까지 프로세스 요청 (! 정지) 동안 { // 다음 소켓 기다립니다 할당 할 소켓 소켓 =) (기다리고 있습니다; (소켓 == NULL을)의 경우 계속; // 프로세스이 소켓의 요청 시도 { 과정 (소켓); } 캐치 (의 Throwable t) { 로그 ( "process.invoke", t); } 이 요청까지 완료 // connector.recycle (이); } }
우리는 전화 그를 발견 await
얻기 위해 기다리고 차단하는 방법을 socket
방법을. 전에 그리고 Connector
부르심 assign
할당, 그 이유는 무엇인가?
자세히 살펴 다음 await
과 assign
접근 방식. 이 두 가지 방법의 협력, assign
인수 socket
통지 할 때 await
다음 반환 socket
.
동기화 무효 할당 (소켓 소켓) { // 이전 소켓을 얻을 수있는 프로세서 기다립니다 {(가능) 동안 {하려고 대기를 (); } 캐치 (예외 : InterruptedException 전자) { } } // 스토어 새로 가능한 소켓과 우리의 스레드에 통지 this.socket = 소켓을; 가능 = TRUE; 의 notifyAll (); } 개인 동기화 소켓을 기다리고 () { // 커넥터가 새로운 소켓을 제공하기 위해 기다립니다 {동안 (가능!) {하려고 대기를 (); } 캐치 (예외 : InterruptedException 전자) { } } // 우리가받은 커넥터를 통지이 소켓 소켓 소켓 = this.socket; 가능 = 거짓; 의 notifyAll (); (소켓) 반환; }
기본값은 available
입니다 false
.
그런 다음 충전 요청을 해결 할 일은이 남아 HttpRequest
와 HttpResponse
객체, 다음에 container
책임.
저는 여기에 세부 사항으로 이동하지만, 구문 분석하는 방법을 더
개인 무효 처리 (소켓 socket) { // 파싱 .... connector.getContainer () (요청, 응답)를 호출한다.; .... }
컨테이너
컨테이너는로부터받은 요청을 실행할 수있는 객체입니다 클라이언트를 , 그 요청에 따라 응답을 반환
Container
그것은이 클래스가 구현하는 인터페이스 인터페이스 인스턴스 처리 요구, 해당 통화를 수신 할 수있다 Servlet
.
이 네 가지 범주 있습니다 Container
, 네 Container
하지 사이에 평행하게,하지만 아버지와 아들의 관계는
Engine
- 최상위 컨테이너는 복수를 포함 할 수있다Host
Host
- 가상 나타내는 호스트가 여러 개 포함 할 수 있습니다Context
Context
- 대신web应用
, 즉ServletContext
, 그것은 여러 포함 할 수 있습니다Wrappers
Wrapper
- 대표가Servlet
가장 낮은 레벨이 다른 컨테이너를 포함 할 수 없습니다
컨테이너 통화
컨테이너 가공 공장, 가공 수용 같다 request
, 처리 및 파이프 라이닝은 매우 비슷하지만 조금 다르다. 여기라고 사용됩니다 , 일을 중국어 번역 이다 , 위해 파이프 라인 처리, 가공 도구를 호출을 넣어 메스처럼되고, 당신이 더 추가 할 수있는 도구를 마무리라고 Pipeline
管道
request
Valve
Pipeline
Valve
BaseValve
위의 목록은 더 추상적 인 말의 코드를 살펴 보자 수 있습니다. Engine
상부 용기는, 상기 있도록 invoke
의해 수행되는 Engine
방법. StandardEngine
그것은이 Engine
기본 구현, 또한 구현하고 있습니다 Pipeline
인터페이스를, 그리고 포함 Pipeline
.
그 건설 방법도 지정되어 baseValve
파이프 라인의 마지막 호출입니다, Valve
공공 StandardEngine () { 슈퍼 (); pipeline.setBasic (새 StandardEngineValve ()); }
그럼 우리는 볼 invoke
이 방법에서 상속됩니다 ContainerBase
. 사이 만에 하나 개의 라인, pipeline
처리.
공개 공극 호출 (요청 요청, 응답 응답) IOException이, {ServletException이 발생 pipeline.invoke (요청, 응답); }
다음은 기본입니다 실현, 구현.StandardPipeline
invoke
pipeline
공공 무효의 호출 (요청 요청, 응답 응답) IOException이, ServletException이가 {던졌습니다 // 요청이 파이프 라인의 첫 번째 밸브를 호출 (새 StandardPipelineValveContext ()) invokeNext (요청, 응답).; }
하나 개의 라인! 전화 입니다 방법, 내부 클래스를. 우리가 살펴 보자StandardPipelineValveContext
invokeNext
pipeline
특정 코드
공공 무효 invokeNext (요청 요청, 응답 응답) IOException이, ServletException이 발생을 { INT 첨자 = 단계; 단 스테이지 = + 1; // 현재 요청 스레드 요청 밸브를 호출 하는 경우 (첨자 <valves.length) { 밸브 [첨자] .invoke (요청, 응답이); //加工 } 다른 경우 ((첨자 == valves.length) && (기본 = NULL)!) { basic.invoke (요청, 응답이); } 다른 { 새로운 ServletException을 던질 (sm.getString ( "standardPipeline.noValve을")); } }
그것은 통화를 pipeline
사용 Valve
하기 위해 request
처리를 수행 밸브가 실행될 때 호출 BaseValve
위의 인 StandardEngineValve
,
우리는 보는 invoke
방법
// 선택 호스트이 요청에 사용되는 ) (StandardEngine 엔진 = (StandardEngine) getContainer에; 호스트 = (호스트) 엔진 호스트. 지도 (요청, TRUE); 만약 (호스트 == NULL) { ((HttpServletResponse를) response.getResponse ()) 대해 sendError. (HttpServletResponse.SC_BAD_REQUEST, sm.getString ( "standardEngine.noHost" request.getRequest () getServerName ()).); 반환; } //이 요청 처리하기 위해이 호스트를 물어 host.invoke (요청, 응답);
그것은 통해 (Host) engine.map(request, true);
취득 대응 Host
하고 계속해서 용기를 다음 계층으로 진행한다. 나중에 실행 순서
그리고 Engine
같은, 그러나 많은 내가 갈
요약 실행 순서
긴 뛴 후 invoke
완성 된 용기의 제 1 층의 최종 실행 순서. 난 당신이 내가 여기서 무엇을 조금 현기증, 요약을 볼 것 같아요.
커넥터 -> HttpProcessor.process () -> StandardEngine.invoke () -> StandardPipeline.invoke () ->
StandardPipelineValveContext.invokeNext () -> valves.invoke () -> StandardEngineValve.invoke () ->
StandardHost.invoke ()
여기에 위치하는 Engine
이 층의 끝. 다음이었다 Host
정확히 같은 단계는,
StandardHost.invoke () -> StandardPipeline.invoke () ->
StandardPipelineValveContext.invokeNext () -> valves.invoke () -> StandardHostValve.invoke () ->
StandardContext.invoke ()
그 다음에 Context
이 층의 처리는 마지막에 대응하는 선택 Wrapping
실행된다.
싸개
Wrapper
(A)에 상응하는 Servlet
예를 들면, StandardContext
더 따른 것 request
선택에 대응하는 Wrapper
통화. 우리는 직접 살펴
Wrapper
중 basevalve
전화 할 경우는 방법. 다음은 내가 많이 생략 방법은,Servlet
service
StandardWrapperValve
invoke
키 봐.
공공 무효의 호출 (요청 요청, 응답 응답 ValveContext valveContext)는 IOException가, ServletException이가 {던졌습니다 // 할당 서블릿 이 요청을 처리하기 위해 인스턴스를 경우를 {(사용할 수 없음!) 서블릿 = wrapper.allocate (); } 이 요청에 대한 필터 체인 생성 // 애플리케이션 licationFilterChain filterChain = createFilterChain (요청, 서블릿); //이 요청에 대한 필터 체인 전화 // 참고 :이 또한 방법 서블릿의 service ()를 호출 문자열 JS 경우 (! jspFile = NULL) PFILE = wrapper.getJspFile (); //是否是JSP sreq.setAttribute (Globals.JSP_FILE_ATTR, jspFile); 다른 sreq.removeAttribute (Globals.JSP_FILE_ATTR); 경우 ((서블릿 = NULL) && (filterChain = NULL)!) { filterChain.doFilter (SREQ, SRES); } sreq.removeAttribute (Globals.JSP_FILE_ATTR); }
먼저 호출이 wrapper.allocate()
,이 방법은 매우 중요하다, 그것은 통과 할 것이다 反射
(가) 해당 찾을 우리에게 반환의 예의 파일 구조를. 그런 다음 생성 에 익숙한 당신이 낯선 없어야한다? 이것은 우리가 무엇에 개발 시간의 사용 . 다음의 구현 이 호출 및 방법, 우리는이 방법을보고servlet
class
FilterChain
j2ee
web app
filter
doFilter
internalDoFilter
개인 무효 internalDoFilter (ServletRequest를 요청 ServletResponse를 응답) IOException가이 {ServletException이 발생 존재하는 경우 다음 // 필터 전화 (this.iterator.hasNext ()) {경우 ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) iterator.next (); 필터 filter = NULL; 필터 = filterConfig.getFilter (); filter.doFilter (요청, 응답이); 반환; } 서블릿 인스턴스를 호출 - // 우리는 체인의 끝에 떨어졌다 경우 HttpServletRequest의 instanceof를 ((요청) && HttpServletResponse를 instanceof를 (응답)) { ,의 Servlet.service ((HttpServletRequest의) 요청을 (HttpServletResponse를) 반응); 사용한다} else { 의 Servlet.service (요청, 응답); } }
마지막으로,이 방법은 본 service
지금 당신의 사용을 알고, 방법을 filter
수행하지 않으면 시간 doFilter
, service
이유는 핸들에 의해 실행되지 않습니다.