반응형

GET으로 보낼때 한글깨짐
server.xml에 URIEncoding="EUC-KR" 이나 URIEncoding="UTF-8" 추가

<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="EUC-KR"/>

POST로 보낼때 한글깨짐
모든 jsp와 servlet에서 request.getParameter를 호출하기전에 characterEncoding을 지정해줌
request.setCharacterEncoding("EUC-KR");

이게 싫다면...
web.xml에 필터를 추가해준다
톰캣 6.0인경우 예제 경로는 apache-tomcat-6.0.18\webapps\examples

1. web.xml에 다음을 추가해준다
<filter>
        <filter-name>Set Character Encoding</filter-name>
        <filter-class>filters.SetCharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>EUC-KR</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>Set Character Encoding</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

2. 필터클래스를 만들어줌
예제경로는 apache-tomcat-6.0.18\webapps\examples\WEB-INF\classes\filters\SetCharacterEncodingFilter.java

프로젝트홈\WEB-INF\classes\filters\SetCharacterEncodingFilter.java
에 복사해서 넣어놓자.
반응형

필자는 이전부터 자바 디컴파일러로 JAD를 사용하고 있었다.

물론 이클립스 플러그인을 이용해서 사용했지만 최근에 JD-GUI 에 대하여 알게 되었다.

JAD도 별 불편함 없이 사용하고 있지만 1.4 이후 버전에 대한 지원 소식도 없고 업그레이드도 없는듯 하다.

우선 JD-GUI  윈도우 버전을 다운로드 하여 실행해보았다.

디컴파일 속도도 빠르고 이클립스용 플러그인도 지원하고 있다.

무설치 버전으로 실행하니 일반 에디터와 같은 GUI를 제공하고 있다.

사용하기도 편리하고 무설치에 GUI까지 제공등.. 그리고 지원하는 java 버전등..

이 어찌 매력적이지 않겠는가? 밑에 JD-GUI 사이트 링크를 걸어 놓는다.

http://java.decompiler.free.fr/



GUI 화면 모습이다. 간단히 jar 파일을 실행해 보았다.. 잘 나온다..ㅎㅎ

그리고 디컴파일된 소스는 파일로 저장까지 할수 있다..  꽤 괜찮은것 같다.

이클립스 플러그인 설치는 해당 사이트에 가면 자세히 설명되어 있다.

Eclipse Platform Version: 3.4.1 에서 jD-Eclipse 플러그인 설치 과정이다.

Installation 

Eclipse 3.4 Instructions

우선 Equinox/p2 plug-in 을 설치 하여야 한다.

  1. 이클립스 메뉴에서 Help -> Software Updates...선택하면 아래와 같은 Software Updates and Add-ons 팝업창이 뜬다.

  2. Available Software 탭을 선택한다.
  3. Ganymede tree node 를 확장시킨다.(왼편의 +를 클릭) 
  4. Uncategorized tree node 를 확장시킨다.(왼편의 +를 클릭) 
  5. Equinox p2 Provisioning tree node 에 체크를하고 ,  Install... button 을 클릭한다.



  6. 마지막으로 Finish button 을 클릭하면 된다. 필자의 경우 tjf

Installation of JD-Eclipse plug-in

  1. 이클립스 메뉴에서 Help -> Software Updates...선택하면 아래와 같은 Software Updates and Add-ons 팝업창이 뜬다.
  2. Available Software 탭을 선택한다.
  3. JD-Eclipse plug-in을 new remote site 로 추가:
    1. Add Site... button 을 클릭하면 Add Site 팝업창이 뜬다..
    2. Location 텍스트 박스에 JD-Eclipse update site URL을 타이핑 한다: http://java.decompiler.free.fr/jd-eclipse/update 그리고 OK button 클릭..



  4. Software Updates and Add-ons 창에 추가된 JD-Eclipse Plug-in 을 체크하고, 오른쪽에 있는 Install... button 을 클릭한다.



  5. 다음 화면에서 , Finish button을 클릭
  6. 다음화면에서, Java Decompiler Eclipse Plug-in certificate box 가 나오면 체크를 하고 OK button 을 클릭하면 완료...  

Introduction

The “Java Decompiler project” aims to develop tools in order to decompile and analyze Java 5 “byte code” and the later versions.

JD-Core is a freeware library that reconstructs Java source code from one or more “.class” files. JD-Core may be used to recover lost source code and explore the source of Java runtime libraries. New features of Java 5, such as annotations, generics or type “enum”, are supported. JD-GUI and JD-Eclipse include JD-Core library.

JD-GUI is a standalone graphical utility that displays Java source codes of “.class” files. You can browse the reconstructed source code with the JD-GUI for instant access to methods and fields.

JD-Eclipse is a plug-in for the Eclipse platform. It allows you to display all the Java sources during your debugging process, even if you do not have them all.

JD-Core, JD-GUI and JD-Eclipse are free for non-commercial use. This means that JD-Core, JD-GUI and JD-Eclipse shall not be included or embedded into commercial software products. Nevertheless, these projects may be freely used for personal needs in a commercial or non-commercial environments.

반응형
<출처: http://frogdaddy.tistory.com/entry/weblogic61에서charset변경작업 >
1. 작업 환경

OS: Windows2003 
웹브라우저 : ie7.0 
웹서버/WAS : weblogic6.1 
JAVA : jdk1.3
DB : EUC-KR charset 환경 
      ( DB 도 utf-8 로 바뀌어야 완벽한 작업이 될것으로 예상됨 , 
        나중에 기회가 되면 DB 의 charset 변경작업을 하게되면 blog 로 작성하겠음...)


2. 작업내용

(1) web.xml  파일 수정  : euc-kr 을 utf-8 로
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
  <context-param>
    <param-name>weblogic.httpd.inputCharset./*</param-name>
    <param-value>UTF-8</param-value>  
 </context-param>
</web-app>

(2) weblogic.xml  파일 수정  : euc-kr 을 utf-8 로
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE weblogic-web-app PUBLIC "-//BEA Systems, Inc.//DTD Web Application 6.1//EN" "http://www.bea.com/servers/wls610/dtd/weblogic-web-jar.dtd">
<weblogic-web-app>
  <jsp-descriptor>
    <jsp-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </jsp-param>
  </jsp-descriptor>
  <charset-params>  
    <input-charset>      
      <resource-path>./*</resource-path>      
      <java-charset-name>UTF-8</java-charset-name>    
    </input-charset>  
  </charset-params>
</weblogic-web-app>
 
(3) JSP 의 charset 지정 : euc-kr 을 utf-8 로
<%@ page language="java" contentType="text/html; charset=utf-8" %>

(4) HTML 의  meta tag 의 charset 지정 : euc-kr 을 utf-8 로
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">



3. 유의사항

* ultraediter, jbuilder 로 charset 을 변경한 후 저장하면, weblogic 에서 null pointer exception 오류가 발생함.
   웹셔핑으로 얻은 지식으로 여러가지 방법을 해보았으나, 잘 되지 않았음 ㅠㅠ'

   (utf-8 로 charset 을 지정하면 위 editor 가 file type 설정을 변경시키는듯 합니다. 
    BOM 의 영향이 있는것 같기도 하고.. 
    eclipse 에서 charset 을 utf-8 로 수정한후 저장한 파일을 ultraedit 에서 수정하면 위 오류 발생하지 않음)

* eclipse 에서 편집한후 저장하면 위 오류는 발생하지 않았음.
   ( 기존 jbuilder 에서 작업한 파일시스템을 eclipse 로 import 작업이 필요함)



4. 기존 File Directory ( 웹 directory ) 를  Eclipse 에서 작업하는 방법

(1) 기존 eclipse 의 프로젝트의 폴더의 '.project' , '.classpath' 를  eclipse 에서 작업할 웹 directory 폴더에 copy 한다.
( '.project' , '.classpath' 의 내용을 적당히 수정한다. 내용 수정없이도 import 가 되긴 했는데... ^^; )

(2) eclipse -> File -> Import 
-> General -> Existing Projects into Workspace 
-> 위에 '.project' , '.classpath' copy 된 폴더 선택
반응형

개발 도구

  1. Eclipse : http://www.eclipse.org/
  2. Netbean : http://www.netbeans.org/community/releases/60/index.html
  3. Firebug : http://www.getfirebug.com/

소스코드 관리

  1. CVS : http://www.cvshome.org
  2. Subversion : http://subversion.tigris.org
  3. MS Visual SourceSafe
  4. BitKeeper : http://www.bitkeeper.com
  5. ClearCase : http://www-306.ibm.com/software/awdtools/clearcase/

빌드 스크립트 도구

  1. make : http://source.redhat.com/cygwin
  2. Automake : http://www.gnu.org/software/automake
  3. Ant : http://ant.apache.org
  4. NAnt : http://nant.sourceforge.net
  5. Groovy : http://groovy.codehaus.org
  6. Rake : http://rake.rubyforge.org/  
  7. SCons : http://www.scons.org/

빌드 시스템

  1. Mavenhttp://maven.apache.org 
  2. Maven2 : http://maven.apache.org/maven2/index.html

CI 도구 (Continuous integration )

  1. CruiseControl : http://cruisecontrol.sourceforge.net
  2. CruiseControl .NET : http://sourceforge.net/projects/ccnet
  3. DamageControl : http://damagecontrol.codehaus.org
  4. AntHill : http://www.urbancode.com/projects/anthill
  5. Continuum : http://maven.apache.org/continuum
  6. LuntBuild : http://luntbuild.javaforge.com/  
  7. Buildix : http://buildix.thoughtworks.com/  
  8. Hudson : https://hudson.dev.java.net/  (직관적이고 사용법이 쉬움)

이슈 추적 도구

  1. Bugzilla : http://www.bugzilla.org
  2. JIRA : http://www.atlassian.com/software/jira/default.jsp
  3. FogBugz : http://www.fogcreek.com/FogBugz
  4. PR-Tracker : http://www.prtracker.com  
  5. Trac : http://trac.edgewall.org/

테스트 프레임워크

  1. JUnit : http://www.junit.org
  2. NUnit : http://www.nunit.org
  3. xUnit.NET : http://www.codeplex.com/xunit
  4. MbUnit : http://www.mbunit.org
  5. HTMLUnit : http://htmlunit.sourceforge.net
  6. HTTPUnit : http://httpunit.sourceforge.net
  7. JWebUnit : http://jwebunit.sourceforge.net
  8. Cobertura : http://cobertura.sourceforge.net
  9. Clover : http://www.cenqua.com/clover  
  10. Cactus : http://jakarta.apache.org/cactus/
  11. Emma : http://emma.sourceforge.net/
  12. Fit : http://fit.c2.com
  13. Fitness : http://fitnesse.org  
  14. Watir : http://wtr.rubyforge.org
  15. Systir : http://atomicobject.com/systir.page
  16. AUT : http://aut.tigris.org/
  17. UnitTest++ : http://unittest-cpp.sourceforge.net/  
  18. TestNG : http://testng.org/doc/  
  19. CppUnit : http://sourceforge.net/projects/cppunit  
  20. CppUnit2 : http://cppunit.sourceforge.net/cppunit-wiki/CppUnit2  
  21. Selenium : http://www.openqa.org/
  22. Agitar : http://www.agitar.com/  
  23. JTest : http://www.parasoft.com/jsp/home.jsp  
  24. PushToSoft : http://www.pushtotest.com/  
  25. Eclemma : http://www.eclemma.org/

프로젝트 관리

  1. OpenProj : http://openproj.org/openproj 
  2. dotproject : http://www.dotproject.net/
  3. Mantis : http://www.mantisbt.org/

커뮤니케이션 도구, 위키

  1. MoinMoin : http://moinmoin.wikiwikiweb.de/
  2. Confluence : http://www.atlassian.com/software/confluence/
  3. TWiki : http://twiki.org/
  4. SocialText : http://www.socialtext.com/  
  5. Springnote : http://www.springnote.com/ko

성능분석

  1. ANTS Load : http://www.red-gate.com/products/ants_load/index.htm  
  2. JunitPerf : http://www.clarkware.com/software/JUnitPerf.html  
  3. Jmeter : http://jakarta.apache.org/jmeter/

기타

  1. Structure101 : http://www.headwaysoftware.com/index.php  
  2. FreeMind : http://freemind.sourceforge.net/wiki/index.php/Main_Page  
  3. Capistrano : http://manuals.rubyonrails.com/read/book/17
출처 :   개발이 좋아 개발자가된 많은 사람들에게 말하고 싶은 이야기. by k16wire
반응형
당연히 가장 먼저 할 일은 JCL 라이브러리를 받는 것이다. 아파치 다운로드 페이지로 간다.
 
현재 최신 버전은 1.0.4 (2004년 11월 8일 기준)
 
주요 클래스(인터페이스)를 살펴 보면 딸랑 두개다. 로깅을 담당하는 인터페이스인 Log와 Log 인스턴스를 만들어내는 팩토리 클래스인 LogFactory.
 
물론, JCL은 단지 API 역할만 하기 때문에 Log 인터페이스를 상속한 Log 객체를 쓰게 될 것이다.
 
JCL에서 지원하는 로그 수위는 Log4J와 JDK의 중간인 6단계다.
  1. trace (the least serious)
  2. debug
  3. info
  4. warn
  5. error
  6. fatal (the most serious)
실제 로깅을 수행할 때, 초보자가 가장 어려운 부분은 설정일 것이고, 그 후에는 효율적인 로깅을 할 수 있는 노하우나 절차를 익히는 것이다. 설정에 대해 배워보자.
 
JCL을 사용하는 이점 중에 하나는 JCL에 대해서는 설정할 것이 없다는 점이다. 다만, 구현체로 Log4J나 JDK 로깅을 쓰기 위해 이를 위한 설정만 해주면 된다. 어떻게 이것이 가능할까? 물론, JCL에서 이러한 작업을 수행하기 때문에 가능한 것이다. JCL에 포함된 LogFactoryImpl 클래스의 아래와 같은 코드가 이러한 매직을 만드는 것이다.
 
최대한 개발자의 편의를 위해서 commons-logging.properties 파일에 사용하게될 구현체를 설정하지 않으면, 아래 분기문을 수행하면서 Log4J가 사용 가능한지, JDK1.4가 사용 가능한지, Lumberjack 로깅이 사용 가능한지를 순서대로 살펴본다. 따라서, Log4J, JDK 1.4 로깅을 사용할 경우는 JCL에 대한 별도 설정이 필요없다. 여기서 JDK 1.4 기반에서 Log4J를 사용한다면, Log4J가 사용될 것이라는 점을 짐작할 수 있다. 먼저 logClassName이 설정되고 나면, 이후의 if문에서는 선행조건인 (logClassName == null)에서 걸리기 때문이다.
 
 
        if ((logClassName == null) && isLog4JAvailable()) {
            logClassName = "org.apache.commons.logging.impl.Log4JLogger";
        }
        if ((logClassName == null) && isJdk14Available()) {
            logClassName = "org.apache.commons.logging.impl.Jdk14Logger";
        }
        if ((logClassName == null) && isJdk13LumberjackAvailable()) {
            logClassName = "org.apache.commons.logging.impl.Jdk13LumberjackLogger";
        }
        if (logClassName == null) {
            logClassName = "org.apache.commons.logging.impl.SimpleLog";
        }
        return (logClassName);
 
 
아래와 같이 로그 문장 하나를 만들어보자.
 
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 *
 * @author 안영회
 * @since 2004. 11. 8
 */
public class CommonsLoggerExample {
    private static final Log logger
     = LogFactory.getLog(CommonsLoggerExample.class.getName());

   
    public static void main(String[] args) {
       
        logger.info("hello, log");
       
    }
}
 
아래와 같은 출력문을 만날 수 있다. JDK 1.4 이상을 사용했고, Log4J를 설치하지 않았기 때문이다.
 
2004. 11. 8 오후 2:29:46 CommonsLoggerExample main
정보: hello, log
 
출력 형식과 어디에 출력할 것인가는 어떻게 결정된 것일까? JDK 설치 디렉토리 하위의 JRE/lib 디렉토리에서 logging.properties 파일을 찾을 수 있다. 여기서 JDK 로깅 관련 설정을 하게 된다.
 
############################################################
#   Default Logging Configuration File
#
# You can use a different file by specifying a filename
# with the java.util.logging.config.file system property. 
# For example java -Djava.util.logging.config.file=myfile
############################################################
############################################################
#   Global properties
############################################################
# "handlers" specifies a comma separated list of log Handler
# classes.  These handlers will be installed during VM startup.
# Note that these classes must be on the system classpath.
# By default we only configure a ConsoleHandler, which will only
# show messages at the INFO and above levels.
handlers= java.util.logging.ConsoleHandler
# To also add the FileHandler, use the following line instead.
#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler
# Default global logging level.
# This specifies which kinds of events are logged across
# all loggers.  For any given facility this global level
# can be overriden by a facility specific level
# Note that the ConsoleHandler also has a separate level
# setting to limit messages printed to the console.
.level= INFO
############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################
# default file output is in user's home directory.
java.util.logging.FileHandler.pattern = %h/java%u.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter
# Limit the message that are printed on the console to INFO and above.
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

############################################################
# Facility specific properties.
# Provides extra control for each logger.
############################################################
# For example, set the com.xyz.foo logger to only log SEVERE
# messages:
com.xyz.foo.level = SEVERE
logging.properties 파일의 내용이다. 천천히 살펴보자.

#   Default Logging Configuration File
#
# You can use a different file by specifying a filename
# with the java.util.logging.config.file system property. 
# For example java -Djava.util.logging.config.file=myfile
 
디폴트 로깅 설정 파일이라는 것이고, -D 옵션을 넣어서 실행하여, java.util.logging.config.file 프로퍼티를 키로 설정 파일을 다른 것으로 지정할 수 있다는 것이다.

#   Global properties
# "handlers" specifies a comma separated list of log Handler
# classes.  These handlers will be installed during VM startup.
# Note that these classes must be on the system classpath.
# By default we only configure a ConsoleHandler, which will only
# show messages at the INFO and above levels.
handlers= java.util.logging.ConsoleHandler
# To also add the FileHandler, use the following line instead.
#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler
 
전역 설정. 즉, 로깅 전체에 영향을 미치는 설정을 나타낸다. handlers 프로퍼티는 로그 Handler 클래스 설정에 사용되는데, 로그 핸들러(log handler)가 여러 개인 경우에는 콤마로 구분하여 나열한다. 로그 핸들러 클래스는 당연히 클래스패스에 위치해야 하고, 디폴트는 INFO 이상의 로그 수위만 화면에 출력하는 ConsoleHandler이다.
 
# Default global logging level.
# This specifies which kinds of events are logged across
# all loggers.  For any given facility this global level
# can be overriden by a facility specific level
# Note that the ConsoleHandler also has a separate level
# setting to limit messages printed to the console.
.level= INFO
 
모든 로거에 기본적으로 적용할 로그 수위는 INFO라는 것이다.
 
############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################
# default file output is in user's home directory.
java.util.logging.FileHandler.pattern = %h/java%u.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter
# Limit the message that are printed on the console to INFO and above.
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
 
특정 핸들러에만 적용시킬 프로퍼티. 자세한 내용은 파일 로거를 쓰면서 확인해보자.

############################################################
# Facility specific properties.
# Provides extra control for each logger.
############################################################
# For example, set the com.xyz.foo logger to only log SEVERE
# messages:
com.xyz.foo.level = SEVERE
특정 퍼시리티에만 적용시킬 프로퍼티, 핸드러별 설정보다 더 미세하게 특정 로거단위로도 설정이 가능하다.
 
# show messages at the INFO and above levels.
handlers= java.util.logging.ConsoleHandler
# To also add the FileHandler, use the following line instead.
#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler
 
위와 같은 설정을 아래처럼 바꿔서 파일 로그 핸들러도 쓰이도록 해보자.
 
# show messages at the INFO and above levels.
# handlers= java.util.logging.ConsoleHandler
# To also add the FileHandler, use the following line instead.
handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler
 
어디에 출력이 되었을까? 힌트는 logging.properties 파일의 파일 핸들러 관련 설정이다.
 
# default file output is in user's home directory.
java.util.logging.FileHandler.pattern = %h/java%u.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter
 
%h는 뭔가? JDK FileHandler API 문서에서 설명을 찾을 수 있다.
  • "/" the local pathname separator
  • "%t" the system temporary directory
  • "%h" the value of the "user.home" system property
  • "%g" the generation number to distinguish rotated logs
  • "%u" a unique number to resolve conflicts
  • "%%" translates to a single percent sign "%"
     
    %hHome directory를 의미하는 것이다. 운영체제 그리고 윈도우의 경우는 버전에 따라 디렉토리가 조금씩 다르다. 기본적으로 NT 기반인 경우(필자는 XP Pro), "C:Documents and Settings로그인한 사용자 이름"이다. 홈 디렉토리 밑에 java로 시작하고, %u에 따라 파일이름에 의한 충돌을 방지하기 위한 일련번호를 붙힌다. 확장자는 log.
     
    그래서, 필자의 경우는 홈 디렉토리에 java0.log라는 파일이 생겼다. 다른 위치에 파일이 출력되도록 변경해보자.
     
    java.util.logging.FileHandler.pattern = mylog_%u.log
     
    위와 같이 변경한 후 로그가 출력되는 프로그램을 실행시키자. 클래스 파일을 실행시킨 위치에 mylog0.log라는 이름으로 파일이 생길 것이다. 나머지 설정들의 의미를 알아보자.
     
    java.util.logging.FileHandler.limit = 50000
    하나의 파일에 최대로 기록될 바이트수를 대략적으로 지정한 것이다. 디폴트는 0이며, 무제한이다.

    java.util.logging.FileHandler.count = 1
    출력파일을 몇 개 사용할 것인가. 디폴트는 1.

    java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter
    출력 포맷을 결정하는 포맷터 클래스. 기본적으로 SimpleFormatter와 XMLFormatter가 있으며, 디폴트는 XMLFormatter이다.
     
    SimpleFormatter를 사용한 경우의 출력과 XMLFormatter를 사용한 경우의 출력은 아래와 같다.
     
    SimpleFormatter 사용시
    2004. 11. 8 오후 4:49:34 CommonsLoggerExample main
    정보: hello, log
     
    XMLFormatter 사용시
    <?xml version="1.0" encoding="x-windows-949" standalone="no"?>
    <!DOCTYPE log SYSTEM "logger.dtd">
    <log>
    <record>
      <date>2004-11-08T16:37:25</date>
      <millis>1099899445360</millis>
      <sequence>0</sequence>
      <logger>CommonsLoggerExample</logger>
      <level>INFO</level>
      <class>CommonsLoggerExample</class>
      <method>main</method>
      <thread>10</thread>
      <message>hello, log</message>
    </record>
    </log>
     

  • 반응형
    달송
    http://blog.naver.com/drub5?Redirect=Log&logNo=130033212540
    알송을 Java로 만든거라고 합니다.


    자테온
    http://blog.kfmes.com/category/JaTeOn
    네이트온을 Java로 만든것입니다.


    다들 개발자분들이 자작하신 프로그램입니다.
    반응형

    자바 컴파일과 실행 에 사용되어지는 javac, java 명령어의 옵션 을 다음과 같이 정리하였습니다.

    javac - 자바컴파일러로써, 자바코드를 작성한 소스파일(.java)을 자바 가상머신이 인식할수 있는 바이트 코드(.class)
    타입으로 변환시켜주는 명령어 입니다.

    사용법: javac <options> <souce files>
    예를들어, Hello.java, Greeting.java 두개의 파일이 존재한다면,
    javac Hello.java Greeting.java
    javac *.java (*을 사용해서, 모든 확장자가 .java인 파일을 컴파일할수 있다.)

    1) 옵션:


    a) -classpath:

     -classpath(cp) path(파일 절대 경로):
     컴파일러가 컴파일 하기 위해서 필요로 하는 참조할 클래스 파일들을 찾기 위해서 컴파일시 파일 경로를 지정해주는
    옵션. 예를 들어,  Hello.java파일이 C:\Java 디렉터리에 존재하고, 필요한 클래스 파일들이 C:\Java\Engclasses에 위치한다면,
    javac -classpath C:\Java\Engclasses C:\Java\Hello.java 로 해주면 된다. 만약 참조할 클래스 파일들이 C:\Java\Engclasses외의
    다른 디렉터리에도 존재한다면, C:\Java\Korclasses 일경우,
    javac -classpath C:\Java\Engclasses;C;\Java\Korclasses C:\Java\Hello.java
    그리고, 현재 디렉터리역시 포함하고 싶다면,
    javac -classpath .;C:\Java\Engclasses;C;\Java\Korclasses C:\Java\Hello.java
    기본적으로, dos에서는 .는 현재 디렉터리를 의미하고, ..는 현재 디렉터리의 상위디렉터리를 의미한다.
    또한 classpath 대신 단축어인 cp를 사용해도 된다.
    javac -cp C:\Java\Engclasses C:\Java\Hello.java 

    b) -d:
     -d directory
     클래스 파일을 생성할 루트 디렉터리를 지정합니다.
    기본적으로 컴파일러는 -d옵션을 주지 않으면, 소스파일이 위치한 디렉터리에 클래스 파일을 생성시킵니다.
    예를 들어,  Hello.java파일이 C:\Java 디렉터리에 존재하고 클래스 파일의 루트디렉터리를 C:\Java\Classfiles라고 하면,
    javac -d C:\Java\Classfiles C:\Java\Hello.java 입니다.

    만약 -d 옵션을 사용하려고 하는데, 루트디렉터리(위예에서는 C:\Java\Classfiles) 가 존재 하지 않는다면,
    "The system cannot find the path specified"라는 에러 메시지를 보게 됩니다.
    현재 작업 디렉터리가 C:\Java\Classfiles 에 위치하면,
    javac -d .\Classfiles Hello.java 와 같이 상대 디렉터리로 표현할수 있습니다.

    c) -encoding:
    -encoding encoding name
    소스 파일에 사용된 문자열 인코딩을 설정합니다.
    만약 위옵션이 설정되어 있지 않으면, 플래폼의 기본적인 컨버터가 사용되어 집니다.

    d) -g:
    모든 디버깅 정보를 생성시킵니다.
    만약 위옵션이 설정되어 있지 않으면, 기본적으로, 라인넘버만 생성시킵니다.
    -g:none: 디버깅 정보를 전혀 생성 시키지 않습니다.
    -g:{lines, vars, source}:
    위처럼 명시적으로, 몇몇 디버깅 정보를 생성시킬수 있습니다.
    lines은 라인정보, vars는 지역변수, sounce는 소스 파일 정보를 나타냅니다.

    e) -nowarn:

    경고 메시지 (warning message)를 생성시키지 않습니다.

    f) -verbose:

    컴파일러와 링커가 현재 어느 소스파일이 컴파일되고 있고, 어느 파일이 링크되고 있는지
    그정보를 출력한다.

    h) -deprecation:

    소스 코드내에서, 사용되어진 deprecated API의 위치 를 출력 합니다.

    ex)
    C:\Java> javac World.java
    Note: World.java uses a deprecated API. Recompile with "-deprecation" for details
    .
    1 warning
    C:\Java> javac -deprecation World.java
    World.java:52: Note: The method java.awt.Dimension size() in class java.awt.Compon
    ent has been deprecated.
    Dimension d = size();

    Note: World.java uses a deprecated API. Please consult the documentation for a be
    tter alternative.

    i) -sourcepath:

    -sourcepath 소스패스

    소스파일의 위치를 지정합니다.

    j) -target:

    -target 자바버젼

    지정된 자바버젼의 VM에서 작동 되어지도록 클래스파일을 생성 시킵니다.

    1.1
    jvm 1.1 버젼에서 호환되어질수 있는 클래스 파일생성
    1.2
    jvm 1.2 버젼에서 호환되어질수 있는 클래스 파일생성
    1.3
    jvm 1.3 버젼에서 호환되어질수 있는 클래스 파일 생성

    ex)

    javac -target 1.2 Helloworld.java

    k) -bootclasspath 패스:

    특정한 bootstrap또는 확장 클래스를 지정할수 있다.
    기본적으로, 자바컴파일러는 javac(컴파일러명령)이 설치된 플래폼의 bootstrap과 확장클래스들을 통해서, 컴파일작업을 수행하지만,
    bootclasspath 옵션을 사용하면, cross-compiling이라고 해서, 다른 자바플래폼의 bootstrap과 확장클래스들을 통해서, 컴파일 할수 있는 기능을 지원한다.
    예를들어,
    javac -target 1.1 -bootclasspath jdk1.1.7/lib/classes.zip -extdirs "" OldCode.java
    컴파일러에게 현재 자신의 bootstrap을 사용하지 말고, jdk1.1.7/lib/classes.zip bootstrap클래스들을 사용해서 컴파일 하라고
    명령하는것이다.
    참고로, 모바일자바에서, 모바일폰에 설정된, jvm에 맞도록, 소스코드를 컴파일하기 위해서, 주로 사용되어지는 옵션이다.

    l) -extdirs 디렉터리:
    특정한, 확장 디렉토리를 지정한다.cross-compiling시 주로, 사용되어지는 옵션이면, 각디렉터리들은 콜론(:)에 의해서, 분리되어진다.
    컴파일시, 기술한 디렉터리의 클래스 파일을 참조한다.

    자바프로그램(Java Application)을 실행시켜 주는 명령어이다.


    사용법:java <options> <classfiles> <argument> 또는
              java <options> -jar file.jar <argument>

    options: 옵션
    classfiles: 호출될 클래스 파일 이름
    file.jar: 호출될 jar파일 이름
    argument:main함수에 파라미터로 보내질 문자열


    예를들어, main함수를 포함하는 Hello.class 파일이 존재할경우,
    java Hello 로 프로그램을 실행시킬수 있는데, 확장자인 class는 생략할수 있지만,
    대소문자는 구별하므로, 정확하게 기입해야 한다.
    java Hello Greeting 처럼 Greeting을 덧붙일경우, main함수에 문자열인자로 Greeting을 보낼수 있다.

     

    a) -client:
    자바 HotSpot Client VM을 선택한다. (디폴트 값이다)

     

    b) -server:
    자바 HotSpot Server VM을 선택한다.

     

    c) -classpath (-cp):
    참조할 클래스 파일 패스를 지정하는데, jar파일, zip파일, 클래스파일의 디렉터리 위치를 기술한다.
    각 클래스파일 패스는 콜론(:)을 통해서, 분리시켜 기술한다
    자바VM은  자바프로그램을 로딩시, -classpath로 지정된 클래스 패스나, java플래폼이 설치된, 운영체제에서의
    환경변수로 지정된, 클래스패스를 통해서, 클래스 파일들을 참조하게 된다.

     

    d) -D <property name>=<property value>:
    시스템의 property 값을 설정한다.

    ex) java -Djava.library.path=. HelloWorld

    자바의 시스템 property(속성)중 "java.library.path"값을 "." (현재디렉터리)로 지정해서, HelloWorld 실행시켜라는 의미 이다.

    위와같이 자바VM에 지정된 속성을 실행시 -D옵션을 사용해서, 변경, 지정할수 있다.

     

    e) -jar 파일이름:

    jar파일로 압축되어져 있는 자바 프로그램을 실행시킨다.

    클래스 파일이름 대신 jar파일을 사용해서, 압축되어져 있는 자바 프로그램을 실행시킬수 있는데, 위프로그램이 제대로 실행되어지기 위해서, Jar파일안의 manifest라는 텍스트 파일에 Main-Class:classname 같은 형태의 텍스트 라인이 포함되어 있어야 한다.

    그리고, 여기에 기술된 classname은 main함수를 포함하고 있는 클래스 이름이 되어야 한다.

     

    f) -verbose:

    자바프로그램 실행되어지는 정보를 화면에 출력해준다.

    -verbose:class

    로딩되어지는 각클래스들의 정보를 화면에 출력한다.

    -verbose:gc

    garbage collection 이벤트를 화면에 출력한다.

    -verbose:jni

    native 함수들과 다른 자바 native 인터페이스 사용에 대한 정보를 출력한다

     

    g) -version:

    현재 JVM의 버젼 정보만 출력한다

     

    h) -showversion:

    현재 JVM의 버젼정보를 출력한다.

    java -showversion HelloWolrd

    와 같이 자바 프로그램을 실행시키면서, 자바 버젼정보를 출력할수 있다.

     

    i) -X

    비표준 자바옵션 리스트를 화면에 출력해준다.

     

    i-1) -Xms, -Xmx

    자바를 구동시, JVM이 사용가능한 최대 메모리 사이즈를 변경합니다.

    JVM이 자바프로그램을 구동하기 위해, 초기설정된 메모리사이즈는 64M입니다.

    사용방법은 다음과 같습니다

    java -Xms <초기힙사이즈> -Xmx <최대힙사이즈>

    예를들어, Hello.class 자바 프로그램을 시작시, 256M(메가)의 힙사이즈를 할당하며, 최대 512M의 힙사이즈를 할당받고 싶다면,  다음과같이 합니다.

    java -Xms256m -Xmx512m Hello

    ###################################################################

    ###################################################################

    Usage: javac <options> <source files>
    where possible options include:
      -g                                  Generate all debugging info
      -g:none                          Generate no debugging info
      -g:{lines,vars,source}     Generate only some debugging info
      -nowarn                         Generate no warnings
      -verbose                        Output messages about what the compiler is doing
      -deprecation                   Output source locations where deprecated APIs are used
      -classpath <path>           Specify where to find user class files and annotation processors
      -cp <path>                     Specify where to find user class files and annotation processors
      -sourcepath <path>         Specify where to find input source files
      -bootclasspath <path>      Override location of bootstrap class files
      -extdirs <dirs>                Override location of installed extensions
      -endorseddirs <dirs>       Override location of endorsed standards path
      -proc:{none,only}            Control whether annotation processing and/or compilation is done.
      -processor <class1>[,<class2>,<class3>...]

                                          Names of the annotation processors to run; bypasses default discovery process
      -processorpath <path>      Specify where to find annotation processors
      -d <directory>                 Specify where to place generated class files
      -s <directory>                 Specify where to place generated source files
      -implicit:{none,class}      Specify whether or not to generate class files for implicitly referenced files
      -encoding <encoding>       Specify character encoding used by source files
      -source <release>          Provide source compatibility with specified release
      -target <release>            Generate class files for specific VM version
      -version                         Version information
      -help                             Print a synopsis of standard options
      -Akey[=value]                Options to pass to annotation processors
      -X                                 Print a synopsis of nonstandard options
      -J<flag>                         Pass <flag> directly to the runtime system
     
     
     
     
    Usage: java [-options] class [args...]
              (to execute a class)
      or  java [-options] -jar jarfile [args...]
              (to execute a jar file)

    where options include:
       -client   to select the "client" VM
       -server   to select the "server" VM
       -hotspot   is a synonym for the "client" VM  [deprecated]
                     The default VM is client.
                    
       -cp <class search path of directories and zip/jar files>
       -classpath <class search path of directories and zip/jar files>
                     A ; separated list of directories, JAR archives, and ZIP archives to search for class files.
       -D<name>=<value>
                     set a system property
       -verbose[:class|gc|jni]
                     enable verbose output
       -version      print product version and exit
       -version:<value>
                     require the specified version to run
       -showversion  print product version and continue
       -jre-restrict-search | -jre-no-restrict-search
                     include/exclude user private JREs in the version search
       -? -help      print this help message
       -X            print help on non-standard options
       -ea[:<packagename>...|:<classname>]
       -enableassertions[:<packagename>...|:<classname>]
                     enable assertions
       -da[:<packagename>...|:<classname>]
       -disableassertions[:<packagename>...|:<classname>]
                     disable assertions
       -esa | -enablesystemassertions
                     enable system assertions
       -dsa | -disablesystemassertions
                     disable system assertions
       -agentlib:<libname>[=<options>]
                     load native agent library <libname>, e.g. -agentlib:hprof
                       see also, -agentlib:jdwp=help and -agentlib:hprof=help
       -agentpath:<pathname>[=<options>]
                     load native agent library by full pathname
       -javaagent:<jarpath>[=<options>]
                     load Java programming language agent, see java.lang.instrument
       -splash:<imagepath>
                     show splash screen with specified image
     

    M) package 선언된 Java class 실행시키기

    - package위치는 CLASSPATH 하위 폴더부터로 인식한다. 따라서 Package폴더의 Root가 ClassPath에 지정되든지

    .(현위치)를 ClassPath에 등록 후 현 위치 아래서부터 package의 위치를 지정한다.

    java package.class명 (현위치 아래에 package폴더가 존재)

    java com.test.SampleMain

    반응형
    JVM GC와 메모리 튜닝




    자바스터디 네트워크 [www.javastudy.co.kr]

    조대협 [bcho_N_O_SPAM@j2eestudy.co.kr]




    모든 Java Application은 JVM(Java Virtual Machine)위에서 동작한다.
    이 JVM이 동작하는데 있어서, 메모리의 구조와 특히 GC는 Application의 응답시간과 성능에 밀접한 관계를 미친다. 이번 강좌에서는 JVM 의 메모리 구조와 GC 알고리즘 (JDK 1.4.X에 포함된 새로운 알고리즘 포함) 그리고, JVM의 메모리 튜닝을 통한 Application의 성능향상방법에 대해서 알아보도록 하자.


    1.GC란 무엇인가?


    GC는 Garbage Collection의 약자로 Java 언어의 중요한 특징중의 하나이다.
    GC는 Java Application에서 사용하지 않는 메모리를 자동으로 수거하는 기능을 말한다.
    예 전의 전통적인 언어 C등의 경우 malloc, free등을 이용해서 메모리를 할당하고, 일일이 그 메모리를 수거해줘야했다. 그러나 Java 언어에서는 GC 기술을 사용함에 따라서 개발자로 하여금 메모리 관리에서 부터 좀더 자유롭게 해주었다.


    2.GC의 동작 방법은 어떻게 되는가?


    1) JVM 메모리 영역

    GC의 동작 방법을 이해하기 위해서는 Java의 메모리 구조를 먼저 이해할 필요가 있다.
    일반적으로 Application에서 사용되는 객체는 오래 유지 되는 객체보다, 생성되고 얼마안있어서 사용되지 않는 경우가 많다. <그림 1 참조>


    <그림 1. 메모리 foot print>


    그래서 Java에서는 크게 두가지 영역으로 메모리를 나누는데 Young 영역과 Old 영역이 그것이다.
    Young 영역은 생긴지 얼마 안된 객체들을 저장하는 장소이고, Old영역은 생성된지 오래된 객체를 저장하는 장소이다. 각 영역의 성격이 다른 만큼 GC의 방법도 다르다.
    먼저 Java의 메모리 구조를 살펴보자.


    <그림 2. Java 메모리 구조>


    Java의 메모리 영역은 앞에서 이야기한 두 영역 (Young 영역,Old 영역)과 Perm 영역 이렇게 3가지로 영역으로 구성된다.


    <표 1. Java 메모리 영역>



    2) GC 알고리즘

    그러면 이 메모리 영역을 JVM이 어떻게 관리하는지에 대해서 알아보자.
    JVM 은 New/Young 영역과, Old영역 이 두영역에 대해서만 GC를 수행한다. Perm영역은 앞에서 설명했듯이 Code가 올라가는 부분이기 때문에, GC가 일어날 필요가 없다. Perm영역은 Code가 모두 Load되고 나면 거의 일정한 수치를 유지한다.


    ○ Minor GC
    먼저 New/Young영역의 GC방법을 살펴보자 New/Young 영역의 GC를 Minor GC라고 부르는데, New/Young영역은 Eden과 Survivor라는 두가지 영역으로 또 나뉘어 진다. Eden영역은 Java 객체가 생성되자 마자 저장이 되는곳이다. 이렇게 생성된 객체는 Minor GC가 발생할때 Survivor 영역으로 이동된다.

    Survivor 영역은 Survivor 1과 Suvivor2 영역 두 영역으로 나뉘어 지는데, Minor GC가 발생하면 Eden과 Survivor1에 Alive되어 있는 객체를 Suvivor2로 복사한다. 그리고 Alive되어 있지 않는 객체는 자연히 Suvivor1에 남아있게 되고, Survivor1과 Eden영역을 Clear한다. (결과적으로 Alive된 객체만 Survivor2로 이동한것이다.)
    다음번 Minor GC가 발생하면 같은 원리로 Eden과 Survivor2영역에서 Alive되어 있는 객체를 Survivor1에 복사한다. 계속 이런 방법을 반복적으로 수행하면서 Minor GC를 수행한다.

    이렇게 Minor GC를 수행하다가, Survivor영역에서 오래된 객체는 Old영역으로 옮기게 된다.

    이 런 방식의 GC 알고리즘을 Copy & Scavenge라고 한다. 이 방법은 매우 속도가 빠르며 작은 크기의 메모리를 Collecting하는데 매우 효과적이다. Minor GC의 경우에는 자주 일어나기 때문에, GC에 소요되는 시간이 짧은 알고리즘이 적합하다.

    이 내용을 그림을 보면서 살펴보도록 하자.


    <그림 3-1. 1st Minor GC>


    Eden에서 Alive된 객체를 Suvivor1으로 이동한다. Eden 영역을 Clear한다.


    <그림 3-2. 2nd Minor GC>


    Eden영역에 Alive된 객체와 Suvivor1영역에 Alive된 객체를 Survivor 2에 copy한다.
    Eden영역과 Suvivor2영역을 clear한다.


    <그림 3-3. 3rd Minor GC>


    객체가 생성된 시간이 오래지나면 Eden과 Suvivor영역에 있는 오래된 객체들을 Old 영역으로 이동한다.


    ○ Full GC

    Old 영역의 Garbage Collection을 Full GC라고 부르며, Full GC에 사용되는 알고리즘은 Mark & Compact라는 알고리즘을 이용한다. Mark & Compact 알고리즘은 전체 객체들의 reference를 쭉 따라가다면서 reference가 연결되지 않는 객체를 Mark한다. 이 작업이 끝나면 사용되지 않는 객체를 모두 Mark가 되고, 이 mark된 객체를 삭제한다.<그림 4 참고> (실제로는 compact라고 해서, mark된 객체로 생기는 부분을 unmark된 즉 사용하는 객체로 메꾸어 버리는 방법이다.)

    Full GC는 매우 속도가 느리며, Full GC가 일어나는 도중에는 순간적으로 Java Application이 멈춰 버리기 때문에, Full GC가 일어나는 정도와 Full GC에 소요되는 시간은 Application의 성능과 안정성에 아주 큰 영향을 준다.


    <그림 4. Full GC>




    3. GC가 왜 중요한가?


    Garbage Collection중에서 Minor GC의 경우 보통 0.5초 이내에 끝나기 때문에 큰문제가 되지 않는다. 그러나 Full GC의 경우 보통 수초가 소요가 되고, Full GC동안에는 Java Application이 멈춰버리기 때문에 문제가 될 수 있다.
    예를 들어 게임 서버와 같은 Real Time Server를 구현을 했을때, Full GC가 일어나서 5초동안 시스템이 멈춘다고 생각해보자.
    또 일반 WAS에서도 5~10초동안 멈추면, 멈추는동안의 사용자의 Request가 Queue에 저장되었다가 Full GC가 끝난후에 그 요청이 한꺼번에 들어오게 되면 과부하에 의한 여러 장애를 만들 수 있다..
    그래서 원할한 서비스를 위해서는 GC를 어떻게 일어나게 하느냐가 시스템의 안정성과 성능에 큰 변수로 작용할 수 있다.


    4. 다양한 GC 알고리즘


    앞 에서 설명한 기본적인 GC방법 (Scavenge 와 Mark and compact)이외에 JVM에서는 좀더 다양한 GC 방법을 제공하고 그 동작방법이나 사용방법도 틀리다. 이번에는 다양한 GC 알고리즘에 대해서 알아보자. 현재 (JDK 1.4)까지 나와 있는 JVM의 GC방법은 크게 아래 4가지를 지원하고 있다.

    - Default Collector
    - Parallel GC for young generation (from JDK 1.4 )
    - Concurrent GC for old generation (from JDK 1.4)
    - Incremental GC (Train GC)

    1) Default Collector
    이 GC 방법은 앞에서 설명한 전통적인 GC방법으로 Minor GC에 Scavenge를, Full GC에 Mark & compact 알고리즘을 사용하는 방법이다. 이 알고리즘에는 이미 앞에서 설명했기 때문에 별도의 설명을 하지는 않는다.

    JDK 1.4에서부터 새로 적용되는 GC방법은 Parallel GC와 Concurrent GC 두가지 방법이 있다. Parallel GC는 Minor GC를 좀더 빨리하게 하는 방법이고 (Throughput 위주) Concurrent GC는 Full GC시에 시스템의 멈춤(Pause)현상을 최소화하는 GC방법이다.

    2) Parallel GC
    JDK1.3까지 GC는 하나의 Thread에서 이루어진다. Java가 Multi Thread환경을 지원함에도 불구하고, 1 CPU에서는 동시에 하나의 Thread만을 수행할 수 밖에 없기때문에, 예전에는 하나의 CPU에서만 GC를 수행했지만, 근래에 들어서 하나의 CPU에서 동시에 여러개의 Thread를 실행할 수 있는 Hyper Threading기술이나, 여러개의 CPU를 동시에 장착한 HW의 보급으로 하나의 HW Box에서 동시에 여러개의 Thread를 수행할 수 있게 되었다.

    JDK 1.4부터 지원되는 Parallel GC는 Minor GC를 동시에 여러개의 Thread를 이용해서 GC를 수행하는 방법으로 하나의 Thread를 이용하는것보다 훨씬 빨리 GC를 수행할 수 있다.


    <그림 7. Parallel GC 개념도>


    < 그림 7> 을 보자 왼쪽의 Default GC방법은 GC가 일어날때 Thread들이 작업을 멈추고, GC를 수행하는 thread만 gc를 수행한다. (그림에서 파란영역), Parallel GC에서는 여러 thread들이 gc를 수행이 가능하기 때문에, gc에 소요되는 시간이 낮아진다.

    Parallel GC가 언제나 유익한것은 아니다. 앞에서도 말했듯이 1CPU에서는 동시에 여러개의 thread를 실행할 수 없기 때문에 오히혀 Parallel GC가 Default GC에 비해서 느리다. 2 CPU에서도 Multi thread에 대한 지원이나 계산등을 위해서 CPU Power가 사용되기 때문에, 최소한 4CPU의 256M 정도의 메모리를 가지고 있는 HW에서 Parallel GC가 유용하게 사용된다.

    Parallel GC는 크게 두가지 종류의 옵션을 가지고 있는데,Low-pause 방식과 Throughput 방식의 GC방식이 있다.

    Solaris 기준에서 Low-pause Parallel GC는 ?XX:+UseParNewGC 옵션을 사용한다. 이 모델은 Old 영역을 GC할때 다음에 설명할 Concurrent GC방법과 함께 사용할 수 있다. 이 방법은 GC가 일어날때 빨리 GC하는것이 아니라 GC가 발생할때 Application이 멈춰지는 현상(pause)를 최소화하는데 역점을 뒀다.

    Throughput 방식의 Parallel GC는 ?XX:+UseParallelGC (Solaris 기준) 옵션을 이용하며 Old 영역을 GC할때는 Default GC (Mark and compact)방법만을 사용하도록 되어 있다.Minor GC가 발생했을때, 되도록이면 빨리 수행하도록 throughput에 역점을 두었다.

    그외에도 ParallelGC를 수행할때 동시에 몇개의 Thread를 이용하여 Minor영역을 Parallel GC할지를 결정할 수 있는데, -XX:ParallelGCThreads= 옵션을 이용하여 Parallel GC에 사용되는 Thread의 수를 지정할 수 있다.

    3) Concurrent GC

    앞에서도 설명했듯이, Full GC즉 Old 영역을 GC하는 경우에는 그 시간이 길고 Application이 순간적으로 멈춰버리기 때문에, 시스템 운용에 문제가 된다.

    그래서 JDK1.4부터 제공하는 Concurrent GC는 기존의 이런 Full GC의 단점을 보완하기 위해서 Full GC에 의해서 Application이 멈추어 지는 현상을 최소화 하기 위한 GC방법이다.
    Full GC에 소요되는 작업을 Application을 멈추고 진행하는것이 아니라, 일부는 Application이 돌아가는 단계에서 수행하고, 최소한의 작업만을 Application이 멈췄을때 수행하는 방법으로 Application이 멈추는 시간을 최소화한다.


    <그림 8. Concurrent GC 개념도>


    그 림 8에서와 같이 Application이 수행중일때(붉은 라인) Full GC를 위한 작업을 수행한다. (Sweep,mark) Application을 멈추고 수행하는 작업은 일부분 (initial-mark, remark 작업)만을 수행하기 때문에, 기존 Default GC의 Mark & Sweep Collector에 비해서 Application이 멈추는 시간이 현저하게 줄어든다.

    Solaris JVM에서는 -XX:+UseConcMarkSweepGC Parameter를 이용해 세팅한다.

    4) Incremental GC (Train GC)

    Incremental GC또는 Train GC라고도 불리는 GC방법은 JDK 1.3에서부터 지원된 GC방법이다. 앞에서 설명한 Concurrent GC와 비슷하게, 의도 자체는 Full GC에 의해서 Application이 멈추는 시간을 줄이고자 하는데 있다.

    Incremental GC의 작동방법은 간단하다. Minor GC가 일어날때 마다 Old영역을 조금씩 GC를 해서 Full GC가 발생하는 횟수나 시간을 줄이는 방법이다.


    <그림 9. Incremental GC 개념도>


    그 림 9에서 보듯이. 왼쪽의 Default GC는 FullGC가 일어난후에나 Old 영역이 Clear된다. 그러나, 오른쪽의 Incremental GC를 보면 Minor GC가 일어난후에, Old 영역이 일부 Collect된것을 볼 수 있다.

    Incremental GC를 사용하는 방법은 JVM 옵션에 ?Xinc 옵션을 사용하면 된다.
    Incremental GC는 많은 자원을 소모하고, Minor GC를 자주일으키고, 그리고 Incremental GC를 사용한다고 Full GC가 없어지거나 그 횟수가 획기적으로 줄어드는 것은 아니다. 오히려 느려지는 경우가 많다. 필히 테스트 후에 사용하도록 하자.

    ※ Default GC이외의 알고리즘은 Application의 형태나 HW Spec(CPU수, Hyper threading 지원 여부), 그리고 JVM 버전(JDK 1.4.1이냐 1.4.2냐)에 따라서 차이가 매우 크다. 이론상으로는 실제로 성능이 좋아보일 수 있으나, 운영환경에서는 여러 요인으로 인해서 기대했던것만큼의 성능이 안나올 수 있기 때문에, 실환경에서 미리 충분한 테스트를 거쳐서 검증한후에 사용해야 한다.


    5. GC 로그는 어떻게 수집과 분석


    JVM에서는 GC 상황에 대한 로그를 남기기 위해서 옵션을 제공하고 있다.
    Java 옵션에 ?verbosegc 라는 옵션을 주면되고 HP Unix의 경우 ?verbosegc ?Xverbosegc 옵션을 주면 좀더 자세한 GC정보를 얻을 수 있다. GC 정보는 stdout으로 출력이 되기 때문에 “>” redirection등을 이용해서 file에 저장해놓고 분석할 수 있다.

    Example ) java ?verbosegc MyApplication

    그럼 실제로 나온 GC로그를 어떻게 보는지를 알아보자.


    <그림 5. 일반적인 GC 로그, Windows, Solaris>


    <그림 5>는 GC로그 결과를 모아논 내용이다. (실제로는 Application의 stdout으로 출력되는 내용과 섞여서 출력된다.)
    Minor GC는 ”[GC “로 표기되고, Full GC는 “[Full GC”로 표기된다.
    그 다음값은 Heap size before GC인데,GC 전에 Heap 사용량 ( New/Young 영역 + Old 영역 + Perm 영역)의 크기를 나타낸다.

    Heap size after GC는 GC가 발생한후에 Heap의 사용량이다. Minor GC가 발생했을때는 Eden과 Survivor 영역으 GC가 됨으로 Heap size after GC는 Old영역의 용량과 유사하다.(Minor GC에서 GC되지 않은 하나의 Survivor영역내의 Object들의 크기도 포함해야한다.)

    Total Heap Size는 현재 JVM이 사용하는 Heap Memory양이다. 이 크기는 Java에서 ?ms와 ?mx 옵션으로 조정이 가능한데. 예를 들어 ?ms512m ?mx1024m로 해놓으면 Java Heap은 메모리 사용량에 따라서 512~1024m사이의 크기에서 적절하게 늘었다 줄었다한다. (이 늘어나는 기준과 줄어드는 기준은 (-XX:MaxHeapFreeRatio와 ?XX:MinHeapFreeRation를 이용해서 조정할 수 있으나 JVM vendor에 따라서 차이가 나기때문에 각 vendor별 JVM 메뉴얼을 참고하기 바란다.) Parameter에 대한 이야기는 추후에 좀더 자세히하도록 하자.

    그 다음값은 GC에 소요된 시간이다.

    < 그림 5>의 GC로그를 보면 Minor GC가 일어날때마다 약 20,000K 정도의 Collection이 일어난다. Minor GC는 Eden과 Suvivor영역 하나를 GC하는 것이기 때문에 New/Young 영역을 20,000Kbyte 정도로 생각할 수 있다.

    Full GC때를 보면 약44,000Kbyte에서 1,749Kbyte로 GC가 되었음을 볼 수 있다. Old영역에 큰 데이타가 많지 않은 경우이다. Data를 많이 사용하는 Application의 경우 전체 Heap이 512이라고 가정할때, Full GC후에도 480M정도로 유지되는 경우가 있다. 이런 경우에는 실제로 Application에서 Memory를 많이 사용하고 있다고 판단할 수 있기 때문에 전체 Heap Size를 늘려줄 필요가 있다.

    이렇게 수집된 GC로그는 다소 보기가 어렵기 때문에, 좀더 쉽게 분석할 수 있게 하기 위해서 GC로그를 awk 스크립트를 이용해서 정제하면 분석이 용이하다.


    <표 2. gc.awk 스크립트>


    이 스크립트를 작성한후에 Unix의 awk 명령을 이용해서

    % awk ?f gc.awk GC로그파일명

    을 쳐주면 아래<표 3>와 같이 정리된 형태로 GC 로그만 추출하여 보여준다.


    <표 3. gc.awk 스크립트에 의해서 정재된 로그>


    Minor와 Major는 각각 Minor GC와 Full GC가 일어날때 소요된 시간을 나타내며, Alive는 GC후에 남아있는 메모리양, 그리고 Freed는 GC에 의해서 collect된 메모리 양이다.

    이 로그파일은 excel등을 이용하여 그래프등으로 변환해서 보면 좀더 다각적인 분석이 가능해진다.

    ※ JDK 1.4에서부터는 ?XX:+PrintGCDetails 옵션이 추가되어서 좀더 자세한 GC정보를 수집할 수 있다.


    ※ HP JVM의 GC Log 수집

    HP JVM은 전체 heap 뿐 아니라 ?Xverbosegc 옵션을 통해서 Perm,Eden,Old등의 모든 영역에 대한 GC정보를 좀더 정확하게 수집할 수 있다.

    Example ) java ?verbosegc ?Xverbosegc MyApplication ß (HP JVM Only)

    HP JVM의 GC정보는 18개의 필드를 제공하는데 그 내용을 정리해보면 <표 4.>와 같다.

    <GC : %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12 %13 %14 %15 %16 %17 %18>


    <표 4. HP JVM GC 로그 필드별 의미>


    이 로그를 직접 보면서 분석하기는 쉽지가 않다. 그래서, HP에서는 좀더 Visual한 환경에서 분석이 가능하도록 HPJtune이라는 툴을 제공한다. 다음 URL에서 다운로드 받을 수 있다.

    http://www.hp.com/products1/unix/java/java2/hpjtune/index.html


    <그림 6. HP Jtune을 이용해서 GC후 Old영역의 변화 추이를 모니터링하는 화면>




    6. GC 관련 Parameter


    GC 관련 설정값을 보기전에 앞서서 ?X와 ?XX 옵션에 대해서 먼저 언급하자. 이 옵션들은 표준 옵션이 아니라, 벤더별 JVM에서 따로 제공하는 옵션이기 때문에, 예고 없이 변경되거나 없어질 수 있기 때문에, 사용전에 미리 JVM 벤더 홈페이지를 통해서 검증한다음에 사용해야한다.

    1) 전체 Heap Size 조정 옵션

    전체 Heap size는 ?ms와 ?mx로 Heap 사이즈의 영역을 조정할 수 있다. 예를 들어 ?ms512m ?mx 1024m로 설정하면 JVM은 전체 Heap size를 application의 상황에 따라서 512m~1024m byte 사이에서 사용하게 된다. 그림2의 Total heap size

    메모리가 모자를때는 heap을 늘리고, 남을때는 heap을 줄이는 heap growing과 shirinking 작업을 수행하는데, 메모리 변화량이 큰 애플리케이션이 아니라면 이 min heap size와 max heap size는 동일하게 설정하는 것이 좋다. 일반적으로 1GB까지의 Heap을 설정하는데에는 문제가 없으나, 1GB가 넘는 대용량 메모리를 설정하고자 할 경우에는 별도의 JVM 옵션이 필요한 경우가 있기때문에 미리 자료를 참고할 필요가 있다.

    ※ IBM AIX JVM의 경우
    %export LDR_CNTRL=MAXDATA=0x10000000
    %java -Xms1500m -Xmx1500m MyApplication

    2) Perm size 조정 옵션

    Perm Size는 앞에서도 설명했듯이, Java Application 자체(Java class etc..)가 로딩되는 영역이다. J2EE application의 경우에는 application 자체의 크기가 큰 편에 속하기 때문에, Default로 설정된 Perm Size로는 application class가 loading되기에 모자른 경우가 대부분이기 때문에, WAS start초기나, 가동 초기에 Out Of Memory 에러를 유발하는 경우가 많다.

    PermSize는 -XX:MaxPermSize=128m 식으로 지정할 수 있다.
    일반적으로 WAS에서 PermSize는 64~256m 사이가 적절하다.

    3) New 영역과 Old 영역의 조정New 영역은 ?XX:NewRatio=2 에 의해서 조정이 된다.
    NewRatio Old/New Size의 값이다. 전체 Heap Size가 768일때, NewRatio=2이면 New영역이 256m, Old 영역이 512m 로 설정이 된다.
    JVM 1.4.X에서는 ?XX:NewSize=128m 옵션을 이용해서 직접 New 영역의 크기를 지정하는 것이 가능하다.

    4) Survivor 영역 조정 옵션
    -XX:SurvivorRatio=64 (eden/survivor 의 비율) :64이면 eden 이 128m일때, survivor영역은 2m가 된다.

    5) -server와 ?client 옵션
    JVM에는 일반적으로 server와 client 두가지 옵션을 제공한다.
    결 론만 말하면 server 옵션은 WAS와 같은 Server환경에 최적화된 옵션이고, client옵션은 워드프로세서와 같은 client application에 최적화된 옵션이다. 그냥 언뜻 보기에는 단순한 옵션 하나로보일 수 있지만, 내부에서 돌아가는 hotspot compiler에 대한 최적화 방법과 메모리 구조자체가 아예 틀리다.

    ○ -server 옵션

    server 용 application에 최적화된 옵션이다. Server application은 boot up 시간 보다는 user에 대한 response time이 중요하고, 많은 사용자가 동시에 사용하기 때문에 session등의 user data를 다루는게 일반적이다. 그래서 server 옵션으로 제공되는 hotspot compiler는 java application을 최적화 해서 빠른 response time을 내는데 집중되어 있다.

    또한 메모리 모델 역시, 서버의 경우에는 특정 사용자가 서버 운영시간동안 계속 서버를 사용하는게 아니기 때문에 (Login하고, 사용한 후에는 Logout되기 때문에..) 사용자에 관련된 객체들이 오래 지속되는 경우가 드물다. 그래서 상대적으로 Old영역이 작고 New 영역이 크게 배정된다. <그림 7. 참조 >

    ○ -client 옵션

    client application은 워드프로세서 처럼 혼자 사용하는 application이다. 그래서 client application은 response time보다는 빨리 기동되는데에 최적화가 되어 있다. 또한대부분의 client application을 구성하는 object는GUI Component와 같이 application이 종료될때까지 남아있는 object의 비중이 높기 때문에 상대적으로 Old 영역의 비율이 높다.


    <그림 7. ?server와 ?client 옵션에 따른 JVM Old와 New영역>


    이 두옵션은 가장 간단한 옵션이지만, JVM의 최적화에 아주 큰부분을 차지하고 있는 옵션이기 때문에, 반드시 Application의 성격에 맞춰서 적용하기 바란다.
    (※ 참고로, SUN JVM은 default가 client, HPJVM는 default가 server로 세팅되어 있다.)

    ○ GC 방식에 대한 옵션

    GC 방식에 대한 옵션은 앞에서도 설명했지만, 일반적인 GC방식이외에, Concurrent GC,Parallel GC,Inceremental GC와 같이 추가적인 GC Algorithm이 존재한다. 옵션과 내용은 앞장에서 설명한 “다양한 GC알고리즘” 을 참고하기 바란다.


    7.JVM GC 튜닝


    그러면 이제부터 지금까지 설명한 내용을 기반으로 실제로 JVM 튜닝을 어떻게 하는지 알아보도록 하자.

    STEP 1. Application의 종류와 튜닝목표값을 결정한다.

    JVM 튜닝을 하기위해서 가장 중요한것은 JVM 튜닝의 목표를 설정하는것이다. 메모리를 적게 쓰는것이 목표인지, GC 횟수를 줄이는것이 목표인지, GC에 소요되는시간이 목표인지, Application의 성능(Throughput or response time) 향상인지를 먼저 정의한후에. 그 목표치에 근접하도록 JVM Parameter를 조정하는것이 필요하다.

    STEP 2. Heap size와 Perm size를 설정한다.

    -ms 와 ?mx 옵션을 이용해서 Heap Size를 정한다. 일반적으로 server application인 경우에는 ms와 mx 사이즈를 같게 하는것이 Memory의 growing과 shrinking에 의한 불필요한 로드를 막을 수 있어서 권장할만하다.

    ms와mx사이즈를 다르게 하는 경우는 Application의 시간대별 memory 사용량이 급격하게 변화가 있는 Application에 효과적이다.
    PermSize 는 JVM vendor에 따라 다소 차이가 있으나 일반적으로 16m정도이다. Client application의 경우에는 문제가 없을 수 있지만, J2EE Server Application의 경우 64~128m 사이로 사용이 된다.

    Heap Size와 Perm Size는 아래 과정을 통해서 적정 수치를 얻어가야한다.

    STEP 3. 테스트 & 로그 분석.

    JVM Option에 GC 로그를 수집하기 위한 ?verbosegc 옵션을 적용한다. (HP의 경우 ?Xverbosegc 옵션을 적용한다.)

    LoadRunner 나 MS Strest(무료로 MS社의 홈페이지에서 다운로드 받을 수 있다.)와 같은 Strest Test툴을 통해서 Application에 Strest를 줘서. 그 log를 수집한다. 튜닝에서 있어서 가장 중요한것은 목표산정이지만, 그만큼이나 중요한것은 실제 Tuning한 Parameter가 Application에 어떤 영향을 주는지를 테스트하는 방법이 매우 중요하다. 그런 의미에서 적절한 Strest Tool의 선정과, Strest Test 시나리오는 정확한 Tuning을 위해서 매우 중요한 요인이다.

    ○ Perm size 조정
    아래 그림8.은 HP JVM에서 ?Xverbosegc 옵션으로 수집한 GC log를 HP Jtune을 통해서 graph로 나타낸 그래프이다. 그림을 보면 Application이 startup되었을때 Perm 영역이 40m에서. 시간이 지난후에도 50m 이하로 유지되는것을 볼 수 있다. 특별하게 동적 classloading등이 수십m byte가 일어나지 않는등의 큰 변화요인이 없을때, 이 application의 적정 Perm 영역은 64m로 판단할 수 있다.


    <그림 8. GC 결과중 Perm 영역 그래프>


    ○ GC Time 수행 시간 분석

    다음은 GC에 걸린 시간을 분석해보자. 앞에 강좌 내용에서도 설명햇듯이. GC Tuning에서 중요한 부분중 하나가 GC에 소요되는 시간 특히 Full GC 시간이다.

    지금부터 볼 Log는 모社의 물류 시스템의 WAS 시스템 GC Log이다. HP JVM을 사용하며, -server ?ms512m ?mx512m 옵션으로 기동되는 시스템이다.

    그림 9를 보면 Peak 시간 (첫번째 동그라미) 14시간동안에 Full GC(동그란점)가 7번일어난것을 볼 수 있다. 각각에 걸린 시간은2.5~6sec 사이이다.
    여기서 STEP 1.에서 설정한 AP Tuning의 목표치를 참고해야하는데.

    Full GC가 길게 일어나서 Full GC에 수행되는 시간을 줄이고자 한다면 Old 영역을 줄이면 Full GC가 일어나는 횟수는 늘어나고, 반대로 Full GC가 일어나는 시간을 줄어들것이다.

    반대로 Full GC가 일어나는 횟수가 많다면, Old 영역을 늘려주면 Full GC가 일어나는 횟수는 상대적으로 줄어들것이고 반대로 Full GC 수행시간이 늘어날 것이다.

    특 히 Server Application의 경우Full GC가 일어날때는 JVM자체가 멈춰버리기 때문에, 그림 9의 instance는 14시간동안 총 7번 시스템이 멈추고, 그때마다 2.5~6sec가량 시스템이 response를 못하는 상태가 된것이다. 그래서 멈춘 시간이 고객이 납득할만한 시간인지를 판단해야 하고, 거기에 적절한 Tuning을 해야한다.

    Server Application에서 Full GC를 적게일어나게하고, Full GC 시간을 양쪽다 줄이기 위해서는 Old영역을 적게한후에, 여러개의 Instance를 동시에 뛰어서 Load Balancing을 해주면, Load가 분산되기 때문에 Full GC가 일어나는 횟수가 줄어들테고, Old 영역을 줄였기 때문에, Full GC에 드는 시간도 줄어들것이다. 또한 각각의 FullGC가 일어나는동안 하나의 서버 instance가 멈춰져 있어도, Load Balancing이 되는 다른 서버가 response를 하고 있기때문에, Full GC로 인한 Application이 멈추는것에 의한 영향을 최소화할 수 있다.


    <그림 9. GC 소요시간>


    데이타에 따라서 GC Tuning을 진행한후에는 다시 Strest Test를 진행해서 응답시간과 TPS(Throughput Per Second)를 체크해서 어떤 변화를 주었는지를 반드시 체크해봐야한다.


    <그림 10. GC후의 Old 영역>


    그림 10은 GC후에 Old 영역의 메모리 변화량을 나타낸다.

    금 요일 업무시간에 메모리 사용량이 올라가다가. 주말에가서 완만한 곡선을 그리는것을 볼 수 있다. 월요일 근무시간에 메모리 사용량이 매우 많고, 화요일에도 어느정도 메모리 사용량이 있는것을 볼 수 있다. 월요일에 메모리 사용량이 많은것을 볼때, 이 시스템의 사용자들이 월요일에 시스템 사용량이 많을 수 있다고 생각할 수 있고, 또는 다른 주의 로그를 분석해봤을때 이 주만 월요일 사용량이 많았다면, 특별한 요인이나 Application 변경등이 있었는지를 고려해봐야할것이다.

    이 그래프만을 봤을때 Full GC가 일어난후에도 월요일 근무시간을 보면 Old 영역이 180M를 유지하고 있는것을 볼 수 있다. 이 시스템의 Full GC후의 Old영역은 80M~180M를 유지하는것을 볼 수 있다. 그래서 이 시스템은 최소 180M이상의 Old 영역을 필요로하는것으로 판단할 수 있다.

    STEP 4. Parameter 변경.
    STEP 3에서 구한 각 영역의 허용 범위를 기준으로 Old영역과 New 영역을 적절하게 조절한다.
    PermSize와 New영역의 배분 (Eden,Survivor)영역등을 조정한다.
    PermSize 는 대부분 Log에서 명확하게 나타나기 때문에, 크게 조정이 필요가 없고 New영역내의 Eden과 Survivor는 거의 조정하지 않는다. 가장 중요한것은 Old영역과 New 영역의 비율을 어떻게 조정하는가가 관건이다.

    이 비율을 결정하면서, STEP1에서 세운 튜닝 목표에 따라서 JVM의 GC Algorithm을 적용한다. GC Algorithm을 결정하는 기본적인 판단 내용은 아래와 같다.



    이렇게 Parameter를 변경하면서 테스트를 진행하고, 다시 변경하고 테스트를 진행하는 과정을 거쳐서 최적의 Parameter와 GC Algorithm을 찾아내는것이 JVM의 메모리 튜닝의 이상적인 절차이다.


    지금까지 JVM의 메모리 구조와 GC 모델 그리고 GC 튜닝에 대해서 알아보았다.

    정 리하자면 GC 튜닝은 Application의 구조나 성격 그리고, 사용자의 이용 Pattern에 따라서 크게 좌우 되기때문에, 얼마만큼의 Parameter를 많이 아느냐 보다는 얼마만큼의 테스트와 로그를 통해서 목표 값에 접근하느냐가 가장 중요하다.


    출처 : http://www.j2eestudy.co.kr/lecture_data/lecture0401_1_1_index.html
    반응형
     
    출처 Don't Worry~ Be Happy!! | 바간나
    원문 http://blog.naver.com/swucs/40003944891

    MVC 이해하기

    Duncan Mills 지음

    Oracle9i JDeveloper가 Model-View-Controller 디자인 패턴 기반 J2EE 애플리케이션의 구축을 돕는 방법

    필자는 여러분들이 내년 이후에는 MVC (Model-View-Controller) 패턴이라 불리는 디자인 패턴에 대하여 훨씬 더 많이 접하게 될 것이라고 확신합니다. 이번 기고는 그런 의미에서 MVC의 정확한 정의와 언제, 어디서 그리고 어떻게 Oracle9i JDeveloper를 사용하여 MVC 애플리케이션을 구축할 수 있는 지에 대하여 설명할 수 있는 좋은 기회라고 생각합니다.


    이번 기고에서는 우선 디자인 패턴부터 소개를 하고, 그 후에 MVC에 대하여 자세하게 살펴보도록 하겠습니다.

    필수 용어

    J2EE 애플리케이션 디자인을 다룰 때 극복해야 할 첫번째 과제는 새로운 용어들과 특정 소프트웨어 형식 관련 전문 용어들입니다. 그래서 이번 기고에서는 자주 다루게 될 J2EE 관련 중요 개념들을 먼저 살펴본 후 본 내용을 다루도록 하겠습니다

    디자인 패턴

    "디자인 패턴"이라는 용어가 요즘 매우 많이 사용되고 있지만 여기에서 다루고자 하는 것은 프로그래밍 문제 해결을 위한 증명된 시도 방법에 대해서 입니다. 불행하게도 그 용어는 그 동안 남용되어 오면서, 그 자신이 목적이 되곤 했습니다. 소프트웨어는 디자인 패턴에 기반을 둘 수 있고, 그러한 경우에는 소프트웨어의 개발이 더 용이해질 수도 있지만, 소프트웨어를 구입하거나 디자인하는 경우에 기능보다 디자인 패턴을 더 중요하게 여긴다면 역효과를 낼 수도 있습니다.

    "이것이 과연 디자인 패턴을 통해 나를 도울 수 있습니까?"라고 질문하면서 개발 환경을 지켜보는 것은 그리 생산적인 행동은 아닙니다. 디자인 패턴이라는 것은 목적에 대한 수단이 되어야지 결코 그 자체가 목적이 되어서는 안되기 때문입니다. 개발 툴을 평가할 때 할 수 있는 의미 있는 질문은 아마도 "애플리케이션 구축을 위해 이 환경이 얼마나 많은 것을 제공할 수 있습니까?" 정도가 될 것입니다.

    다음은 고려해야 할 중요한 사항들입니다:

    • 디자인 패턴은 비즈니스 문제들을 해결하기 보다는 특정 프로그래밍 과제들을 해결합니다.
    • 디자인 패턴은 실제 구현보다도 가이드라인을 제공합니다.
    • 디자인 패턴은 재사용이 가능합니다
    • 디자인 패턴은 입증된 트랙 기록을 갖고 있습니다.
    현재 웹 상에는 디자인 패턴과 관련된 다양한 정보들이 존재하고 있는데 그 중에서도 Sun Java Blueprints site 사이트는 반드시 확인해 보시기 바랍니다.

    MVC

    MVC는 디자인 패턴 중의 하나로 프로그래밍 세계에서는 전혀 새로울 것이 없습니다. Smalltalk 등과 같은 객체형 프로그래밍의 초기 시대 부터 Java Swing 컴포넌트 집합의 기초를 제공하는 최근까지 디자인 패턴으로서의 MVC 사용과 관련된 많은 레퍼런스들이 존재하고 있습니다. 그런데 MVC가 다시 주목을 받게 된 이유는 그것의 패턴이 웹 기반 애플리케이션 구축 시 발생하는 기본 문제들 중의 대다수를 해결하는데 적합하다는 것을 깨달았기 때문입니다.


    일반적인 데이타베이스-중심 애플리케이션들과 특정한 웹 기반의 씬-클라이언트 애플리케이션들을 살펴보면 애플리케이션이 여러 가지 구분되는 작업들을 수행해야 한다는 것을 발견할 수 있습니다:

    • 데이타 액세스
    • 비즈니스 로직 구현
    • 사용자 인터페이스 표시 (데이타 프리젠테이션)
    • 사용자 상호 작용
    • 애플리케이션 (페이지) 플로우
    MVC 아키텍처 또는 패턴은 사용자가 사용자 인터페이스를 재작성하지 않고 다른 데이타 소스에서 애플리케이션으로 용이하게 플러그할 수 있도록 데이타 프리젠테이션 등과 같은 작업들을 데이타 액세스로부터 분리시켜야만 한다는 전제 조건을 갖고 이러한 작업들의 구분 방식을 제공하고 있습니다.

    지금은 MVC를 여기까지만 살펴보고 나중에 다시 자세하게 살펴보도록 하겠습니다.

    JSP Model 1과 Model 2

    진행을 하기에 앞서 JSP Model 1와 Model 2 아키텍처에 대해 잠시 살펴보도록 하겠습니다. 현재 많은 씬-클라이언트 웹 애플리케이션들은 사용자 인터페이스의 디스플레이 처리 방법으로 JSP (JavaServer Page) 를 사용하고 있습니다. 특히 복잡한 애플리케이션에서 여러 페이지를 함께 연결할 때 사용자는 하나 이상의 "루트"를 갖는 페이지들 사이에서 플로우를 어떻게 제어해야 할지 결정을 해야 합니다. 이러한 문제의 경우 JSP는 두 개의 시도 방법을 갖고 있습니다: Model 1 아키텍처와 Model 2 아키텍처

    Model 1 아키텍처 ( 그림 1) 는 페이지들 사이의 라우팅을 JSP 자체에게 맡깁니다. 그래서 JSP는 하드코딩된 링크를 갖고 있거나 또는 페이지 내에 내장된 이동 (navigation) 로직을 갖고 있어야 합니다. 그러나 이 전략은 하나의 문제를 해결함과 동시에 또 다른 문제를 야기시키는데, 그것은 프리젠테이션과 이동 로직이 섞여있어서 페이지를 쉽게 재사용할 수 없기 때문입니다. 심지어 JSP Model 1를 사용하는 간단한 페이지 플로우들도 쉽게 복잡해질 수 있기 때문에 각각의 페이지는 그것이 링크된 다른 페이지들을 모두 알고 있어야만 합니다.

    Model 1 architecture

    JSP Model 2 (그림 2) 는 이 문제에 대한 해결 방법입니다. Model 2 아키텍처의 경우에 페이지 플로우는 JSP에 의해 처리되지 않습니다. 오히려 아키텍처는 페이지와 함께 제출된 정보를 기반으로 하여 분리된 서블릿이 라우팅을 결정하도록 해주어서 페이지들은 논리적으로 링크된 다른 페이지들을 인식할 필요가 없습니다. 이 서블릿은 Controller라고 호칭되는데, 이것은 이번 기고의 원래 주제인 MVC 패턴과 밀접한 관계를 맺고 있습니다.

    JSP Model 2

    MVC의 상세 내용

    MVC는 애플리케이션을 Model, View 그리고 Controller라고 호칭 되는 세 가지 레이어 또는 기능 영역으로 논리적 방법을 통해 분리한 것입니다.


    MVC와 같은 디자인 패턴은 각기 다른 레벨로 적용될 수 있는데, MVC는 애플리케이션 구축 방법으로서 뿐만 아니라 컴포넌트 레벨에서도 유용한 전략으로 활용될 수 있습니다. 잠시 JSP와 웹으로부터 벗어나서 Java Swing 리스트 박스 (이것은 단순한 컴포넌트이지만 훨씬 더 지역화된 범위에서 세 가지의 MVC 요소들을 모두 보유하고 있습니다) 와 같은 것을 고려해 보는 것도 좋습니다.


    그럼 이제부터 세 가지 레벨을 한번 살펴보도록 하겠습니다:

    The Model

    Model은 애플리케이션 데이타 및 비즈니스 로직의 저장소 (repository) 입니다. 그러나 Model이 데이타베이스를 표시한 것이라고 말하는 것은 너무나 극단적인 표현입니다. 일반적으로 Model 기능의 일부는 데이타베이스 기반 애플리케이션을 통해 데이타를 데이타베이스로부터 읽어 들이거나 또는 데이타를 데이타베이스에 지속시키는 것입니다. View의 데이타 액세스는 데이타를 드러내거나 또는 View를 통해 입력된 데이타를 입증 및 소모하기 위해 비즈니스 로직 레이어를 구현하는 작업도 필요로 하고 있습니다.


    애플리케이션 레벨에서 Model은 표시하는 사용자 인터페이스와 표시되는 비즈니스 데이타 사이의 입증 및 추상화 레이어 처럼 동작을 합니다. 데이타베이스 서버 자체는 단순히 Model을 위한 퍼시스턴스 (persistence) 레이어 입니다.

    The View

    View는 Model 데이타를 렌더링하는 것과 관련이 있습니다. 이제부터는 View를 렌더링하는데 사용되는 다른 기술들에 대하여 살펴볼 예정인데, 보통은 JSP 페이지를 사용하고 있습니다. 여기에서 주목해야 할 것은 View 코드는 사용자 역할에 따라 조건부 데이타 표시와 같은 작업들의 수행 로직을 포함할 수는 있지만 View 코드 자체가 애플리케이션이나 이동 로직을 하드코딩하지는 않는다는 것입니다. 최종 사용자가 View로부터 렌더링 되는 HTML 페이지 내의 동작을 수행할 때에는 이벤트가 Controller에게 제출이 되고 그 다음에 무엇을 할 것인지는 전적으로 Controller에게 달려 있습니다.

    The Controller

    Controller는 이름이 나타내는 것과 같이 전체 패턴의 연결 고리 입니다. View에서 수행된 모든 사용자 동작은 브라우저의 요청 컨텐트에 기반을 두고 프로그래밍 또는 메타데이타에 결합되어 다음에 무엇을 할지를 결정하는 Controller를 통해 제출됩니다.


    Controller들은 여러 가지 다른 방식으로 운영될 수 있습니다. 어떤 것들은 요청들을 정확한 코드로 라우팅하기 위해 URL 인수들을 사용할 것이고 다른 것들은 요청이 제출되어 지는 페이지를 참작할 것입니다. 또한 그 외의 것들은 페이지 제출 시에 무엇을 할지를 알아내기 위해 숨겨진 필드들을 사용할 수도 있습니다. 그런데 MVC 디자인 패턴 자체는 Controller가 어떻게 동작하는지 그리고 단순히 그것의 기능이 무엇인지에 대해 규정을 하고 있지는 않습니다.


    Controller는 여러 가지 구분되는 프로세스들 또는 서블릿들로 만들어져서 전체 Controller 기능의 다른 측면들을 처리할 수 있습니다. 예를 들면, 사용자는 하나의 서블릿이 제어하는 페이지 플로우 컨트롤과 또 다른 서블릿이 제어하는 사용자 인터페이스 이벤트 컨트롤 등과 함께 정확한 하위 Controller에게 디스패치하는 마스터 Controller를 가질 수 있습니다. 이 개념 자체는 다른 디자인 패턴의 주제이기도 합니다: Front-Controller 패턴

    웹 애플리케이션에서의 작동 방식

    MVC 패턴은 요약이 가능하여 그림3 에서와 같이 다이어그램을 사용하는 전통적인 씬-클라이언트 웹 애플리케이션에 적용 시킬 수 있습니다.

    MVC pattern

    이와 같은 웹 애플리케이션에 있어서 명심해야 할 것은 모든 것들은 페이지를 제출하는 사용자에 대한 응답을 통해 발생한다는 것입니다. "다음 10 개의 레코드를 표시하십시오" 등과 같은 간단한 UI 작업은 Controller에 대한 클라이언트 브라우저의 요청에 의해 구현되어 더 많은 데이타가 필요하다는 것을 Model에게 가르쳐 준 후 원래 페이지를 다시 표시할 것입니다. 그런 후에 View가 Model로부터 데이타를 요청할 때에는 다음 10 개의 행들이 표시 가능하게 될 것입니다.

    지금까지는 모든 것이 매우 간단하게 보였고, 언급된 세 개의 부분 모두 명확하게 설명되었습니다:

    1. View를 이루는 개별 페이지들은 다른 페이지들에 대한 관계를 알지 못합니다. 그것들은 단지 "이벤트"를 발생시키고 Controller는 정확한 일이 발생하였다는 것을 보증해 줍니다.
    2. View와 Controller는 기본이 되는 데이타 구조 또는 비즈니스 규칙에 대해서 알지도 못 하고 구현도 하지 않습니다. 그것들은 단순히 Model의 공용 API들을 사용 (consume) 할 뿐입니다

    3. Model은 View나 Controller Model에 대해서 아무 것도 알지 못 합니다.
    MVC 패턴의 본질은 장소에 구애 받음이 없이 애플리케이션의 View와 Model 부분의 재사용을 간편하게 만드는 것이고, 애플리케이션 자체는 본래 데이타 소스와 UI를 의미있는 방식으로 결합하는 Controller 부분에 의해 표현이 됩니다.

    마찬가지로, 이러한 논리적 분리는 사용자가 나머지 애플리케이션을 다시 작성하지 않고 선택하는 기술을 특정 레이어를 위해 변경할 수 있게 해줍니다. 예를 들면, View의 구현을 위해 JSP를 사용하여 애플리케이션을 프로토타입할 수 있지만, XML 메타데이타-방식 서블릿을 통해 이후에 View를 바꾸어 놓는 것도 가능합니다. 이 작업은 Model을 변경함이 없이 Controller을 최소한만 변경하여 이행할 수 있습니다. (Controller에 있어서 이러한 경향은 나중에 다시 한번 자세히 살펴보겠지만 Jakarta Struts와 같은 메타데이타-방식 Controller 프레임워크를 사용하기 위함입니다. 그러므로 View를 교환할 때는 Controller 로직 자체가 아니라 그 메타데이타만 변경하면 됩니다.)

    한번 MVC-기반 애플리케이션의 구현을 시작하게 되면 모든 것들이 보다 복잡해 지고, 프로그래머들은 레이어들 사이에서 논리적인 분리를 계속 유지하기 위해서는 교육을 받아야 합니다. 예를 들어 링크를 하드코딩해서 네비게이션 로직을 JSP로 코딩하는 것이 좋게 보일 수는 있지만, 만약 이것이 구현되면 페이지는 더 이상 사용할 수 없게 될 것입니다.

    레이어들 사이의 라인들이 뚜렷하지 않다는 것도 반드시 인식하고 있어야 합니다. 예를 들면 데이타가 페이지로부터 제출될 때 Struts와 같은 Controller 프레임워크는 JavaBean을 데이타로 채우고 계속 진행하기 위해 빈을 Controller로 전달할 수도 있습니다. 그러면 지금의 그 빈은 View의 일부입니까 아니면 Controller의 일부입니까? 솔직히 말씀드리면 어느 버킷 (bucket) 을 선택해서 그것을 위치시키는가 하는 문제는 그리 중요한 것이 아닙니다. 중요 컴포넌트들 사이에서는 항상 인터페이스 레이어들이 존재할 것입니다. 여기에서 중요하게 여겨야 할 것은 올바른 장소에 정확한 종류의 로직을 유지해야 하는 것입니다.

    실제 상황에서의 MVC

    앞에서는 MVC의 이론을 살펴보았고, 지금부터는 J2EE가 포함하고 있는 기술들과 MVC 기반 애플리케이션 구축 과정을 도울 수 있는 Oracle9i JDeveloper에 대하여 살펴보도록 하겠습니다.
    MVC의 각 부분에 대하여 역할 완수를 위해 사용자가 채택할 수 있는 선택 가능한 구현 방법들이 있는데, 당연히 앞으로 언급할 옵션들은 소모적인 것이 아니라 가능성의 일부를 설명해 주는 것들입니다. 뿐만 아니라 일부 솔루션들은 하나 이상의 MVC 부분도 포함할 것입니다.

    실제 상황에서의 Model

    Model의 역할은 애플리케이션 기능과 관련된 애플리케이션 데이타와 비즈니스 로직을 처리하는 것이라고 알려져 있는데, Model은 단지 여러 레이어로 이루어져서 다음과 같은 작업을 처리하는 것이라고 생각하면 됩니다:

    • 비즈니스 객체 지속
    • 데이타 액세스
    • 비즈니스 서비스 제공
    Enterprise JavaBeans (EJB), JDBC, Web Services, 그리고 Oracle9iAS TopLink 등과 같은 기술들은 모두 Oracle9i JDeveloper Business Components for Java (BC4J)와 같은 완벽한 Model 프레임워크를 통해 가장 생산적인 솔루션을 제공하면서 이러한 작업들의 전부 또는 일부를 이행할 수 있는데, 이 프레임워크는 Model 레이어들의 생산을 위해 선언적인 메타데이타-방식의 시도 방법을 제공하면서 프로그래머들이 로우-레벨 보다는 그들의 코드를 통해 비즈니스 요구 사항들의 해결에 집중할 수 있도록 해줍니다. 그리고 BC4J는 지속성을 위해 EJB를 사용하는 것과 같이 다양한 Model 레이어 작업들을 위해 각각 다른 구현 방법을 사용할 수 있는 유연성을 프로그래머에게 제공하고 있습니다. BC4J와 같은 프레임워크를 사용하게 되면 Model의 사용자들은 (View 개발자들) 데이타 액세스 및 비즈니스 로직 구현에 대한 세부 사항들을 정확하게 알 수가 없고 그들은 단지 추상적 레이어만을 제공 받게 됩니다.

    이번 기고에서는 Model 레이어 구현의 다양한 시도 방법에 대한 상대적 장점에 대해서 많은 부분을 할애하지는 않을 것입니다. 그런데 여기에서 알아야 할 것은 JDeveloper는 Model 내에서 사용자들이 비즈니스 프로세스 프로그래밍 로직에 집중할 수 있게 해주면서 이러한 Model 레이어들을 사용하는 기본 작업을 보다 쉽게 만들 수 있는 툴들을 제공한다는 것입니다.

    예를 들어 사용자는 JDeveloper를 통해 데이타베이스를 찾고 Model의 기본으로 사용할 데이타베이스 테이블들을 선택한 다음 그 테이블들을 직접 UML 클래스 다이어그램으로 끌어놓을 수 있습니다.

    JDeveloper는 사용자가 기본 위저드와 등록 정보 편집기 등을 통해 Model 레이어를 생성할 수 있게 해줍니다. 그리고 동일한 방식으로 기본적인 EJB와 BC4J 클래스들, 메타데이타 그리고 전개 기술자 (deployment descriptor) 등의 정의 작업을 수행할 수도 있습니다. BC4J의 경우에는 사용자가 등록 정보 편집기를 통해 검증과 재사용 가능한 비즈니스 규칙들을 그들 자신의 모델로 적용할 수 있는 능력을 얻게 됩니다.

    실제 상황에서의 View

    일반적으로 사용자 인터페이스를 생성할 때 어떠한 기술을 선택해야할 지 무척 당황해 할 수 있습니다. 다음은 선택 가능한 세 가지 시도 방법입니다:

    • HTML 페이지 생성 Java 코드를 작성하는 Java 서블릿
    • 기본적으로는 HTML 페이지를 생성하지만 Model로부터 데이타를 가져오는 것과 같은 기능들을 수행할 때에는 특별한 태그 또는 스크립틀릿 (scriptlet) 들을 내장하는 JSP
    • 메타데이타-방식 또는 템플릿-방식 프레임워크
    Java 서블릿 방식은 Java 프로그래머들이 많이 선호하는 방식으로서 View-구축에 필요한 요구 사항들을 해결합니다. 모든 것은 프로그램 문자열 내에 내장된 HTML 요소들을 통해 코드 내에서 즉시 처리되어야만 하는데, 이와 같은 방식은 복잡하고 오류가 많이 발생합니다.

    현재 View 생성에 있어서 가장 유명한 기술은 JSP 방식인데, 이것은 페이지를 위한 기본적인 사용자 인터페이스 디자인 툴인 Macromedia Dreamweaver 등과 같은 표준 HTML 편집 툴들의 사용 능력과 그 페이지의 작업 방식과 데이타 바인딩을 처리하기 위한 Java 코드의 내장 능력을 함께 결합한 것입니다. JSP가 최초로 실행이 될 때에는 서블릿으로 컴파일이 되는데, HTML 내에 Java 스니핏 (snippet) 들을 내장하는 방식은 Java 내에 HTML을 내장하는 반대 프로세스보다 훨씬 더 생산적이라고 판명되었습니다

    JSP들은 그것들 내부로 직접 내장되는 Java 코드의 세그먼트들을 갖거나 또는 커스텀JSP 태그들을 사용할 수 있습니다. 태그들은 컴파일 시에 즉시 배치되는 Java 코드를 위한 위치 표시자 (placeholder) 인데 그것들의 재사용이 가능하도록 해주는 API와 함께 디자인되어 사용되고 있습니다. 그래서 프로그래머는 기본적 구현에 대한 지식을 보유하지 않고도 애플리케이션 내에서 태그 라이브러리를 재사용이 가능한 컴포넌트들의 라이브러리처럼 사용할 수 있습니다.

    JSP와 JSP 태그 라이브러리들을 결합하는 것은 View 개발자들에게 막대한 능력을 제공함과 동시에 많은 문제점을 발생시킬 수도 있습니다. 그러한 태그 라이브러리들은 BC4J-기반 모델에 대한 간편한 액세스 기능을 제공하는 Oracle BC4J 태그 등과 같은 특별 라이브러리들부터 Struts 태그 라이브러리와 Java Standard Tag Library (JSTL) 등과 같은 보다 일반적인 "개방형 소스" 라이브러리들 까지 존재합니다.

    프로젝트를 위해 정확한 태그 라이브러리를 선택하는 것은 어려운 일이지만 사용을 위해 선택한 다른 기술들이 그 선택 과정을 이끄는 경우도 가끔 발생할 것입니다. 예를 들어, Model 프레임워크로 BC4J를 사용하고 Controller로 Struts를 사용하기로 결정한 경우 JDeveloper는 사용자에게 이러한 조합을 위해 맞추어진 표준 태그 라이브러리들의 집합을 제공할 것입니다

    View 개발의 마지막 방식은 템플릿-방식 또는 메타데이타-방식 프레임워크를 사용하는 것입니다. 이것의 관련 예는 XML을 선언적으로 사용하여 페이지 정의 방식을 제공하는 JDeveloper 내의 UIX 프레임워크입니다.

    Jakarta Velocity 프로젝트는 또 다른 템플릿-기반 방식을 제공하는데 Velocity는 XML-방식 보다는 Velocity가 대신하는 템플릿 HTML 페이지 내의 특별 마크업을 사용하여 오히려 JSP 페이지처럼 동작합니다.

    이와 같은 메타데이타-방식의 시도 방법은 서블릿 또는 JSP를 사용하는 것보다 많은 이점을 제공할 수 있습니다. 우선, 프레임워크는 UI가 무슨 일을 하고 그것이 어떻게 보이는지를 정의하지만 그것이 어떻게 구현되는지는 정의하지 않기 때문에 다른 장비로부터 출력을 얻어낼 때 동일한 메타데이타 정의를 사용할 수 있습니다 (예를 들면 브라우저 클라이언트로부터 HTML 출력을 얻어내거나 또는 전화로부터 WML 출력을 얻어낼 때). 두 번째는 메타데이타의 선언적 성격이 그것 자신에게 정의 뿐만 아니라 시각 편집기의 사용도 추가해 주고 있습니다. 사용자 인터페이스의 포인트-앤드-클릭 편집은 J2EE 개발자의 생산성을 증가시키기 위한 필수 사항 중 하나입니다.

    실제 상황에서의 Controller

    웹 기반 애플리케이션에 적용되었을 때 Controller 기술이 모든 MVC 컴포넌트들 사이에서 가장 완성된 것은 아닙니다. 이것은 Controller와 View가 혼합된 JSP Model 1 방식이 지금까지 광범위하게 사용되어 왔기 때문입니다. Controller들이 계속 사용되어 온 경우 Controller들은 자체 내에서 성장하면서 Jakarta Struts Controller 프레임워크에 기반을 두는 경향도 갖고 있습니다.

    Struts Controller는 매우 유명한 JSP 애플리케이션 구축용 Controller 프레임워크로서 핵심 Controller 기능을 포함하면서 View 레이어를 위해 많은 태그들을 제공하고 있습니다. Struts는 개별 페이지들을 위해 위치 추상화 (abstraction) 를 정의하는 XML 메타데이타와 페이지들 사이의 실제 흐름을 제어하기 위한 프로그래밍 코드의 혼합된 형태를 사용하고 있습니다. 보다 자세한 정보는 Apache 웹 사이트에서 확인해 보시기 바랍니다.

    JDeveloper는 Struts 구성 파일 편집기 그리고 단순 Struts 또는 Struts, BC4J, JSP UIX 등의 조합을 사용하는 애플리케이션들의 구축을 보다 간편하게 만들어 주는 위저드와 JSP 태그들의 집합을 제공하여 Controller로서의 Struts 사용을 완벽하게 지원하고 있습니다.

    MVC의 미래

    이번 기고의 시작 부분에서 잠시 언급했던 것처럼, MVC는 점차 발전하면서 J2EE 애플리케이션들을 위해 선택 가능한 개발 방법론이 되어가고 있습니다. 우리는 현재 매우 흥미로운 개발들이 (특히 View 및 Controller 분야에서) 진행 중인 것을 보고 있습니다.


    Controller 측면에서 Struts 버전 1.1은 베타 상태에 있는데, 이 새로운 버전은 Struts 1.0 보다 훨씬 더 유연하고 또한 많은 일을 처리할 수 있습니다. 또한 페이지 플로우 정의 작업을 더욱 선언적으로 만들면서 단순 페이지 플로우 이상으로 Controller의 범위를 확대하는 Controller를 통해 보다 많은 일이 수행되고 있습니다.


    페이지 플로우의 시각 모델링이 첫번째 단계인데, 많은 벤더들은 현재 이 기술의 작업을 계속 진행하고 있습니다. 그러나 개발자들이 웹 배치를 위해 보다 복잡한 시스템을 구축하기 시작하면서 단순 페이지 플로우 보다는 전체 프로세스들을 모델링하는 능력에 대한 요구가 점차 증가하고 있습니다. 이와 같은 프로세스들 중에서 페이지를 최종 사용자에게 보여주는 것은 플로우를 위해 가능한 여러 작업들 중의 하나일 뿐입니다. Oracle은 매우 가까운 미래에 이와 같은 종류의 Controller 기술을 통해 흥미로운 개발들을 제공할 예정입니다!

    View 측면에서 커다란 변화는 JavaServer Faces (JSF) 입니다. 이것의 목적은 HTML을 위해 J2EE를 사용하여 그래픽 인터페이스의 새로운 표준을 개발하는 것이고, 개념은 표준 UI 요소들과 이벤트 핸들링을 통해 Swing GUI Toolkit과 같은 것을 HTML을 위해 제공하는 것입니다.

    Oracle은 Java Community Process (JSR 127) 의 일부로 정의되고 있는 이 과제의 정의 프로세스에 참여하고 있고, 표준 작업이 종료되자 마자 JSF를 구현할 예정입니다. JSF에 대한 보다 자세한 사항은 http://www.jcp.org/en/jsr/detail?id=127을 확인해 보시기 바랍니다.

    JavaServer Faces는 MVC의 Model에 영향을 미치고 있습니다. 표준화된 GUI 툴킷이라는 것은 View와 Model 사이의 상호 작용이 Model 데이타를 특정 필드 또는 컨트롤로 바인딩을 해서 표준화가 될 수 있다는 것을 의미합니다. 그래서 필자는 J2EE 개발을 위한 패턴으로서 MVC를 사용하는 흥미로운 단계에 접어들었다고 믿고 있습니다. 이 기술은 이제 막 성숙한 단계에 접어들었고 또한 표준화 작업도 함께 이루어지고 있습니다.


    비즈니스 프로그래머들의 작업을 간편하게 해줄 수 있는 시각적 모델러와 UI 편집기를 통해 코드-중심의 애플리케이션 구축으로부터 선언적 컴포넌트 어셈블리로 현재 이동하고 있고, 보다 많은 프레임워크들은 J2EE-관련 표준 및 디자인 패턴의 구현을 위해 통합되어서, 프로그래머들은 코드 작성보다는 비즈니스 문제 해결에 좀 더 집중할 수 있게 되었습니다.

    Duncan Mills는 Oracle Application Development Tools 그룹의 제품 관리자로서 Oracle9i JDeveloper와 Oracle9i Forms의 전문가인데 1988년 이후로 DBA 또는 개발자로서 Oracle 제품을 담당해 왔습니다. 

    반응형

    실무에서 SQL문을 작성하다 보면 동적인 쿼리문 작성을 작성해야 할 때가 많이 있다.

    이때 지겹게 if~else if 문을 통해 아주 지저분한 소스 코드를 생성할 때가 왕왕 있게 마련이다.

    이때 ibatis에서는 아주 깔금하게 구현할 수 있는 방법을 제공해 준다.

     

    <statement id="dynamicGetAccountList" resultMap="account-result">

      select * from account

      <dynamic prepend="WHERE">

        <isNotNull prepend="AND" property="firstName">

          (acc_first_name = #firstName#

        <isNotNull prepend="OR" property="lastName">

           acc_last_name = #lastName#

        </isNotNull>

        )

        </isNotNull>

        <isNotNull prepend="AND" property="emailAddress">

          acc_email like #emailAddress#

        </isNotNull>

        <isGreaterThan prepend="AND" property="id" campareValue="0">

          acc_id = #id#

        </isGreaterThan>

      </dynamic>

      order by acc_last_name

    </statement>

     

    상황에 의존적인 위 동적 statement로 부터 각각 다른 16가지의 SQL문이 생성될 수 있다. if-else구조와 문자열 연결을 코딩하는 경우 수백라인이 필요할 수도 있다.

    동적 statement를 사용하는 것은 몇몇 조건적인 태그를 추가하는 것처럼 간단하게 작성할 수 있다.

     

    이러한 조건들에 대해 간단히 정리하면 아래와 같다.

     

    바이너리 조건 요소-바이너리 조건 요소는 정적값 또는 다른 프로퍼티값을 위한 프로퍼티값과 비교한다. 만약 결과가 true라면 몸체부분의 SQL쿼리가 포함된다.

     

    바이너리 조건 속성

    prepend

    Statement에 붙을 오버라이딩 가능한 SQL부분(옵션)

    property

    비교되는 property(필수)

    compareProperty

    비교되는 다른 property (필수 또는 compareValue)

    compareValue

    비교되는 값(필수 또는 compareProperty)

     

    <isEqual>

    프로퍼티가 값 또는 다른 프로퍼티가 같은지 체크

    <isNotEqual>

    프로퍼티가 값 또는 다른 프로퍼티가 같지 않은지 체크

    <isGreaterThan>

    프로퍼티가 값 또는 다른 프로퍼티 보다 큰지 체크

    <isGreaterEqual>

    프로퍼티가 값 또는 다른 프로퍼티 보다 크거나 같은지 체크

    <isLessThan>

    프로퍼티가 값 또는 다른 프로퍼티 보다 작은지 체크

    <isLessEqual>

    프로퍼티가 값 또는 다른 프로퍼티 보다 작거나 같은지 체크

     

    사용법 예제)

    <isLessEqual prepend="AND" property="age" compareValue="18">

      ADOLESCENT = 'TRUE'

    </isLessEqual>

     

    단일 조건 요소-단일 조건 요소는 특수한 조건을 위해 프로퍼티의 상태를 체크한다.

    prepend

    statement에 붙을 오버라이딩 가능한 SQL부분(옵션)

    property

    체크하기 위한 프로퍼티(필수)

     

    <isPropertyAvailable>

    프로퍼티가 유효한지 체크

    (이를 테면 파라미터의 프로퍼티이다.)

    <isNotPropertyAvailable>

    프로퍼티가 유효하지 않은지 체크

    (이를 테면 파라미터의 프로퍼티가 아니다.)

    <isNull>

    프로퍼티가 null인지 체크

    <isNotNull>

    프로퍼티가 null이 아닌지 체크

    <isEmpty>

    Collection, 문자열 또는 String.valueOf() 프로퍼티가 null이거나 empty(“” or size() < 1)인지 체크

    <isNotEmpty>

    Collection, 문자열 또는 String.valueOf() 프로퍼티가 null 이아니거나 empty(“” or size() < 1)가 아닌지 체크

     

    사용법 예제)

    <isNotEmpty prepend="AND" property="firstName">

      FIRST_NAME = #firstName#

    </isNotEmpty>


    다른 요소들

    Parameter Present : 파라미터 객체가 존재하는지 체크

    Parameter Present Attributes : prepend - the statement에 붙을 오버라이딩 가능한 SQL부분

    <isParameterPresent>

    파라미터 객체가 존재(not null)하는지 체크

    <isNotParameterPresent>

    파라미터 객체가 존재하지(null) 않는지 체크

     

    사용법 예제)

    <isNotParameterPresent prepend="AND">

    EMPLOYEE_TYPE = 'DEFAULT'

    </isNotParameterPresent>


    Iterate : 이 태그는 Collection을 반복하거나 리스트내 각각을 위해 몸체 부분을 반복한다.

    Iterate Attributes :

      prepend - the statement에 붙을 오버라이딩 가능한 SQL부분 (옵션)

      property - 반복되기 위한 java.util.List타입의 프로퍼티 (필수)

      open - 반복의 전체를 열기 위한 문자열, 괄호를 위해 유용하다. (옵션)

      close - 반복의 전체를 닫기 위한 문자열, 괄호를 위해 유용하다. (옵션)

      conjunction - 각각의 반복 사이에 적용되기 위한 문자열, AND 그리고 OR을 위해 유용하다. (옵션)

    <iterate>

    java.util.List 타입의 프로퍼티 반복


    사용법 예제)

    <iterate prepend="AND" property="userNameList" open="(" close=")" conjunction="OR">

    username = #userNameList[]#

    </iterate>


    주의:iterator요소를 사용할 때 리스트 프로퍼티의 끝에 중괄호[]를 포함하는 것은 중요하다. 중괄호는 문자열처럼 리스트를 간단하게 출력함으로부터 파서를 유지하기 위해 리스트처럼 객체를 구별한다.

    + Recent posts