- 인트로
웹어플리케이션이 개발이 끝난 후 배치를 할 서버가 개발서버와 다른 경우이거나,
하나의 패키지를 여러 사이트에 설치하게 된 경우,,
혹은 어떤 제약상 컴파일된 jsp클래쓰외에 자바파일이나 jsp source 자체를 지워야 하는 경우..
jsp 파일이 이미 컴파일(precomiled) 되어있지 않았다면
요청을 받은 서버는 최초 요청시에 jsp->java->class 상태로 변환이 되고,
이 때 발생하는 오버헤드가 서버의 성능(물리적인 머신의 퍼포먼스) 여하에 따라 문제가 될 수 있으며
이러한 변환을 해야하는 jsp (혹은 fragment)들이 수백(많게는 수천) 페이지가 된다면
최초에 각 페이지를 요청한 사람들은 느릿느릿한 페이지 전송 속도에 무척이나 답답하게 될 것입니다.
또한 이번에 작업한 패키지를 여러 사이트에 설치하게 되면서 가뜩이나 느린 서버들이 몇 군데 있어
프리컴파일의 필요를 느껴 간단하게 제작하였습니다.
이 소스 코드의 아이디어는 록스(빨간책.. 팬입니다.) professional jsp 2nd의
프리컴파일 프로토콜(쿼리 스트링에 jsp_precompile 을 이용한)에서 아이디어를 얻었으며,
책 소스중 Precompile class 에 jsp 파일을 검색(재귀를 이용하여 하위 디렉토리까지 검사)하는 기능 정도를
추가한 것입니다.
프리컴파일이 진행되는것을 모니터링하기 위해서 log4j를 간략하게 add-on 시켜 봤습니다.
한빛 ITexpertModel2 jsp 책을 참조했습니다.(강력하고 매우 좋았습니다. 필자분들께 감사를 표합니다.)
역시나 isDebugEnabled() 메서드등이 훌륭한거 갔습니다.
- 설치
log4j api(jar)와 log4j.properties파일을 클래스패쓰가 인식할수 있는 곳에 배치
PreCompiler.java 파일을 컴파일/실행
(PreCompiler class는 메인을 포함한 한 클래스로 구현된 간단한 구조입니다.
- 실행
[root@www ext]# java PreCompiler www.jazzvm.net 80 struts /xxx/webapps/struts/
INFO (PreCompiler.java:66) - ############# constructor initiated!! #############
INFO (PreCompiler.java:67) - target server : www.jazzvm.net
INFO (PreCompiler.java:68) - given port : 80
INFO (PreCompiler.java:69) - webmodule(context) : struts
INFO (PreCompiler.java:70) - context directory(absolute dircetory path)
:/xxx/webapps/struts/
DEBUG (PreCompiler.java:127) - found JSP : /xxx/webapps/struts/loginFb.jsp
DEBUG (PreCompiler.java:159) - [41 / 6]/struts/loginFb.jsp?jsp_precompile
DEBUG (PreCompiler.java:127) - found JSP : /xxx/webapps/struts/main.jsp
DEBUG (PreCompiler.java:159) - [41 / 6]/struts/main.jsp?jsp_precompile
DEBUG (PreCompiler.java:127) - found JSP : /xxx/webapps/struts/admin.jsp
DEBUG (PreCompiler.java:159) - [41 / 6]/struts/admin.jsp?jsp_precompile
DEBUG (PreCompiler.java:127) - found JSP : /xxx/webapps/struts/error.jsp
DEBUG (PreCompiler.java:159) - [41 / 6]/struts/error.jsp?jsp_precompile
DEBUG (PreCompiler.java:127) - found JSP : /xxx/webapps/struts/login.jsp
DEBUG (PreCompiler.java:159) - [41 / 6]/struts/login.jsp?jsp_precompile
INFO (PreCompiler.java:88) - #### total 5 file precompiled ####
[root@www ext]#
- 소스
/*
* @(#)PreCompiler.java
*
* Copyright (c) 2002 Jazz Virtual Machine, Inc.
* HaeUnDae, Busan, Korea. All rights reserved.
*
* 저작권자 표시는 삭제 할 수 없습니다.
* 저작권자 표시를 삭제 하지 않는 경우에 한하여
* 소스의 수정/재배포는 자유롭게 할 수 있으며
* 기능 개선이 되었을 경우 반드시 알릴 필요는 없습니다.
*/
package net.jazzVM.jsp;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import org.apache.log4j.Logger;
/**
* 서브디렉토리의 jsp파일을 검색하여 프리(pre)컴파일을 실행하는 클래스
* 당연히 타겟서버가 기동하고 있어야 함
* visible을 제공하는 메서드는 현재 컨스트럭터와 build 2가지 뿐
*
* @version v0.0 2003. 7. 25.
* @author Yoon YongHyun(jazzvm)
*/
public class PreCompiler {
/** apache log4j를 사용하기 위한 Logging 대상 클래스 */
private static Logger logger =
Logger.getLogger(PreCompiler.class.getName());
/** jsp precompile기능을 사용하기 위해 URL에 어팬드할 쿼리스트링 */
private final static String queryString = "?jsp_precompile";
/** 서버 host name (dns혹은 ip) */
private String host;
/** 포트번호 */
private int port;
/** 웹모듈(컨텍스트)네임 */
private String webmoduleName;
/** 웹모듈(컨텍스트)까지의 실제 경로 */
private String baseDirectory;
/** 프리컴파일이 실행된 갯수를 저장하는 변수 */
private int compiledCount = 0;
/**
* 디폴트 컨스트럭터(사용할 수 없음)
*/
private PreCompiler() throws Exception {
throw new Exception("can't use default constructor!!");
}
/**
* 사용가능한 컨스트럭터
* 멤버 필드 셋팅
* (추후 디폴트 포트에 대한 PreCompiler(url, webmoduleName, baseDirectory)
* 와 같은 시그너처의 컨스트럭터 오버라이딩이 요구됨)
*
* @param url
* @param port
* @param webmoduleName
* @param baseDirectory
*/
public PreCompiler(String host,
int port,
String webmoduleName,
String baseDirectory)
{
this.host = host;
this.port = port;
this.webmoduleName = webmoduleName;
this.baseDirectory = baseDirectory;
if(logger.isInfoEnabled()) {
logger.info("############# constructor initiated!! #############");
logger.info("target server : " + host);
logger.info("given port : " + port);
logger.info("webmodule(context) : " + webmoduleName);
logger.info("context directory(absolute path) :" + baseDirectory);
}
}
/**
* 빌드를 시작하는 메서드
*
* @throws Exception
*/
public void build() throws Exception {
File file = new File(baseDirectory);
if(!file.isAbsolute() || !file.isDirectory()) {
throw new RuntimeException("절대경로가 아니거나 디렉토리가 아닙니다");
}
traceJSPs(file);
if(logger.isInfoEnabled()) {
logger.info("#### total " + compiledCount +
" file precompiled ####");
}
}
/**
* baseDirectory 이하에서 jsp확장자나 jspf를 가진 파일을 검색하고
* 검색이 된경우 프리컴파일을 실행
* 만약 디렉토리를 만나면 하위디렉토리를 모두 검색할때까지 재귀호출
*
* @param file
* @throws Exception
*/
private void traceJSPs(File file) throws Exception {
if(file.isFile()) {
if(file.getName().endsWith(".jsp") ||
file.getName().endsWith(".jspf")
) {
precompile(file);
}
} else if(file.isDirectory()) {
File[] sub = file.listFiles();
for(int i=0; i<sub.length; i++) {
traceJSPs(sub[i]);
}
}
}
/**
* 타겟서버에 접속하여 프리컴파일 시도
* urlStream등은 받지 않음
* MalformedURLException이 발생하는 경우
* log4j를 이용한 error comment(precompile은 계속 시도)
*
* @param file
* @throws Exception
*/
private void precompile(File file) throws Exception {
if(logger.isDebugEnabled()) {
logger.debug("found JSP : " + file.getAbsolutePath());
}
try {
URL target = new URL("http", host, port, makeURLString(file));
target.getContent();
} catch (MalformedURLException e) {
logger.error("error encounted : can't create obj ");
}
compiledCount++;
}
/**
* URL object를 위한 URLString의 템플릿을 제공하는 메서드
*
* @param file
* @return
*/
private String makeURLString(File file) {
StringBuffer buff = new StringBuffer();
buff.append("/");
if(!webmoduleName.equals("ROOT") || !webmoduleName.equals("/")) {
buff.append(webmoduleName);
}
int matchPoint = 0;
String fileName = file.getAbsolutePath().replace('\\', '/');
matchPoint = fileName.indexOf(webmoduleName) + webmoduleName.length();
buff.append(fileName.substring(matchPoint));
buff.append(queryString);
if(logger.isDebugEnabled()) {
logger.debug("[" + fileName.indexOf(webmoduleName) +
" / " + webmoduleName.length() + "]" + buff);
}
return buff.toString();
}
public static void main(String[] args) throws Exception {
/*
[usage] :
String host = "www.jazzvm.net";
String port = "80";
String webmodulename = "jazzweb";
String baseDirectory = "D:\\AntPublishHome\\upload";
String baseDirectory = "E:\\eclipse_projects\\integrator";
*/
String url = "";
int port = 0;
String webmodulename = "";
String baseDirectory = "";
if(args.length != 4) {
System.out.println("[usage] : java dns(or IP) port contextName " +
"contextDir(absolute dir)");
System.out.println("example : java www.jazzvm.net 80 jazzvm " +
"/usr/web/tomcat/webapps/jazzvm");
try {
throw new Exception("error encounted : Invalid argument");
} catch(Exception e) {
System.exit(0);
}
}
url = args[0];
try {
port = Integer.parseInt(args[1]);
} catch(NumberFormatException e) {
System.out.println("port number(2nd arg) must be int type value!!");
}
webmodulename = args[2];
baseDirectory = args[3];
PreCompiler instance =
new PreCompiler(url, port, webmodulename, baseDirectory);
instance.build();
}
}
log4j.properties
log4j.rootLogger=DEBUG, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p (%F:%L) - %m%n
출처
http://okjsp.pe.kr/bbs?act=VIEW&bbs=bbs4&seq=34227&pg=0&keyfield=subject&keyword=&pact=&password=