JSP 가 어떻게 servlet 로 컴 파일 되 어 서 비 스 를 제공 하 는 지 에 대해 논 하 다.
서버 가 대외 적 으로 JSP 요청 서 비 스 를 제공 하 는 것 은 JspServlet 로 HttpServlet 에서 계승 합 니 다.핵심 서비스 입 구 는 service 방법 이 고 대체적으로 다음 과 같다.
소스 코드 분석
먼저 JspServlet 의 핵심 논 리 를 보면 주로 jspUri 를 얻 고 JspServletWrapper 를 얻 는 것 입 니 다.각각 입구 service 방법 과 serviceJspFile 방법 입 니 다.코드 는 다음 과 같 습 니 다(부분).
/**
* jspUri, serviceJspFile
*/
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String jspUri = this.jspFile;
String pathInfo;
if (jspUri == null) {
pathInfo = (String)request.getAttribute(Constants.JSP_FILE);
if (pathInfo != null) {
jspUri = pathInfo;
request.removeAttribute(Constants.JSP_FILE);
}
}
if (jspUri == null) {
jspUri = (String)request.getAttribute("javax.servlet.include.servlet_path");
if (jspUri != null) {
pathInfo = (String)request.getAttribute("javax.servlet.include.path_info");
if (pathInfo != null) {
jspUri = jspUri + pathInfo;
}
} else {
jspUri = request.getServletPath();
pathInfo = request.getPathInfo();
if (pathInfo != null) {
jspUri = jspUri + pathInfo;
}
}
}
boolean precompile = this.preCompile(request);
this.serviceJspFile(request, response, jspUri, precompile);
}
/**
* JspServletWrapper, JspServletWrapper.service
*/
private void serviceJspFile(HttpServletRequest request, HttpServletResponse response, String jspUri, boolean precompile) throws ServletException, IOException {
JspServletWrapper wrapper = this.rctxt.getWrapper(jspUri);
if (wrapper == null) {
synchronized(this) {
wrapper = this.rctxt.getWrapper(jspUri);
if (wrapper == null) {
if (null == this.context.getResource(jspUri)) {
this.handleMissingResource(request, response, jspUri);
return;
}
wrapper = new JspServletWrapper(this.config, this.options, jspUri, this.rctxt);
this.rctxt.addWrapper(jspUri, wrapper);
}
}
}
try {
//
wrapper.service(request, response, precompile);
} catch (FileNotFoundException var8) {
this.handleMissingResource(request, response, jspUri);
}
}
그리고 JspServletWrapper.service 방법(부분 코드)에 들 어 갑 니 다.
// reload volatile
private volatile boolean reload = true;
public void service(HttpServletRequest request, HttpServletResponse response, boolean precompile) throws ServletException, IOException, FileNotFoundException {
Servlet servlet;
try {
if (this.ctxt.isRemoved()) {
throw new FileNotFoundException(this.jspUri);
}
// development firstTime( )
if (!this.options.getDevelopment() && !this.firstTime) {
if (this.compileException != null) {
throw this.compileException;
}
} else {
synchronized (this) {
this.firstTime = false;
// JspCompilationContext.compile
this.ctxt.compile();
}
}
// servlet
servlet = this.getServlet();
if (precompile) {
return;
}
}
try {
// SingleThreadModel
if (servlet instanceof SingleThreadModel) {
synchronized (this) {
servlet.service(request, response);
}
} else {
servlet.service(request, response);
}
}
}
여 기 는 주로 JSpCompilation Context.com plie 방법 을 봅 니 다.
public void compile() throws JasperException, FileNotFoundException {
this.createCompiler();
if (this.jspCompiler.isOutDated()) {
if (this.isRemoved()) {
throw new FileNotFoundException(this.jspUri);
}
try {
//
this.jspCompiler.removeGeneratedFiles();
// jspLoader, null, JspLoader
this.jspLoader = null;
// jsp servlet , AntCompiler JDTCompiler, JDTCompiler
this.jspCompiler.compile();
// reload true, reload
this.jsw.setReload(true);
this.jsw.setCompilationException((JasperException) null);
}
}
}
isOutDated 방법 에 대한 판단 에 주의해 야 합 니 다.요청 할 때마다 jsp 파일 이 업데이트 되 었 는 지 확인 하 는 것 이 아니 라 간격 이 있 습 니 다.만약 에 이번 업데이트 시간 이 지난번 업데이트 검사+간격 내 에 간격 을 초과 하지 않 았 다 면 jsp 파일 의 업 데 이 트 를 검사 하지 않 았 을 것 입 니 다.이것 이 바로 우리 가 말 한 jsp 열 업데이트 지연 시간 입 니 다.isOutDated 는 Compiler 의 방법 입 니 다.다음 과 같 습 니 다(일부 코드).
public boolean isOutDated(boolean checkClass) {
if (this.jsw != null && this.ctxt.getOptions().getModificationTestInterval() > 0) {
//getModificationTestInterval ,
if (this.jsw.getLastModificationTest() + (long)(this.ctxt.getOptions().getModificationTestInterval() * 1000) > System.currentTimeMillis()) {
return false;
}
this.jsw.setLastModificationTest(System.currentTimeMillis());
}
Long jspRealLastModified = this.ctxt.getLastModified(this.ctxt.getJspFile());
if (jspRealLastModified < 0L) {
return true;
} else {
long targetLastModified = 0L;
File targetFile;
if (checkClass) {
targetFile = new File(this.ctxt.getClassFileName());
} else {
targetFile = new File(this.ctxt.getServletJavaFileName());
}
if (!targetFile.exists()) {
return true;
} else {
targetLastModified = targetFile.lastModified();
if (checkClass && this.jsw != null) {
this.jsw.setServletClassLastModifiedTime(targetLastModified);
}
if (targetLastModified != jspRealLastModified) {
if (this.log.isDebugEnabled()) {
this.log.debug("Compiler: outdated: " + targetFile + " " + targetLastModified);
}
return true;
} else if (this.jsw == null) {
return false;
}
}
}
또한,여 기 는 JSP 의 컴 파일 작업 과 관련 되 어 있 습 니 다.컴 파일 작업 은 주로 org.apache.jsper.copiler.Compiler 컴 파일 러 가 맡 습 니 다.Compiler 는 추상 적 인 유형 입 니 다.apache-jsp 에서 두 가지 실현 을 제공 합 니 다.AntCompiler 와 JDTCompiler,기본 적 으로 사용 하 는 컴 파일 러 는 JDTCompiler 입 니 다.마지막 으로 JspServletWrapper.getServlet 방법 으로 돌아 가기:
private volatile boolean reload = true;
public Servlet getServlet() throws ServletException {
//reload volatile boolean
//
if (this.reload) {
synchronized (this) {
if (this.reload) {
//
this.destroy();
Servlet servlet;
try {
InstanceManager instanceManager = InstanceManagerFactory.getInstanceManager(this.config);
// serlvet , getJspLoader
servlet = (Servlet) instanceManager.newInstance(this.ctxt.getFQCN(), this.ctxt.getJspLoader());
} catch (Exception var6) {
Throwable t = ExceptionUtils.unwrapInvocationTargetException(var6);
ExceptionUtils.handleThrowable(t);
throw new JasperException(t);
}
servlet.init(this.config);
if (!this.firstTime) {
this.ctxt.getRuntimeContext().incrementJspReloadCount();
}
this.theServlet = servlet;
this.reload = false;
}
}
}
return this.theServlet;
}
이 를 통 해 알 수 있 듯 이 방법 에서 이중 검 측 체 제 를 사용 하여 과부하 가 필요 한 지 여 부 를 판단 하고 reload 매개 변 수 는 volatile 수식 으로 가시 성 을 확보 합 니 다.새로운 servlet 인 스 턴 스 를 만 들 때 classLoader 는 JspCompilation Context.getJspLoader 방법 으로 얻 었 습 니 다.이 방법의 논 리 를 보십시오.
public ClassLoader getJspLoader() {
if (this.jspLoader == null) {
this.jspLoader = new JasperLoader(new URL[]{this.baseUrl}, this.getClassLoader(), this.rctxt.getPermissionCollection());
}
return this.jspLoader;
}
앞의 JspCompilation Context.coplie 의 논리 에서 jsp 파일 이 업데이트 되 었 음(만 료)이 감지 되면 jspLoader 는 null 로 설 정 됩 니 다.이때 새로운 jspLoader(JasperLoader)를 만 들 고 새로운 loader 를 사용 하여 새로운 servlet 를 불 러 와 jsp 의 열 업 데 이 트 를 완료 합 니 다.오래된 classloader 는 나중에 GC 에서 직접 회수 합 니 다.JSP 가 servlet 로 어떻게 컴 파일 되 고 서 비 스 를 제공 하 는 지 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 관련 JSP 가 servlet 로 컴 파일 된 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 바 랍 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
VScode에서 MVN, Tomcat, JSP/Servlet에서 웹 앱 개발 메모Java와 maven 설치 ( ) 플러그인을 VScode에 설치 Tomcat DL ( ) ※ 환경에 따라 Tomcat 버전을 선택하십시오 Tomcat을 DL하면 zip을 압축 해제하고 모든 디렉토리에 넣습니다. ma...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.