Whiteship's Note


[스프링 3.0] 로깅은 SLF4J를 이용한 Log4J로

Spring/3.0 : 2010.01.28 17:08


스프링을 사용하면 기본적으로 JCL(자카르타 커먼스 로깅)을 사용하게 되는데 JCL이 실제 로거를 선택하는 시점이 런타임이라 클래스로더 문제라던가 런타임시 오버헤드가 생길 수 있는데 이것을 개선한 구현체 SLF4J로 갈아타면 그러너 문제 걱정을 덜 수 있겠습니다. 보너스로 문자열 연결로 발생하는 오버 헤드도 개선할 수 있으며 귀찮은 if문 추가하는 코딩에서 벗어날 수 있는 문법? API?를 제공해줍니다. 그래서인지 스프링도 3.0부터는 본격적으로 spring-core가 의존하는 JCL을 SLF4J로 교체하고 사용하는 예제 및 레퍼런스 설명을 보여주고 있습니다..

갈아타는 방법은 다음과 같습니다.

1. 스프링에서 참조하는 JCL 라이브러리를 빼버리기.
2. JCL-over-SLF4J 추가하기.
3. SLF4J API 추가.
4. SLF4J-log4j 추가.
5. log4j 추가.

이전에 스프링소스 블로그와 레퍼런스에 올라온 방법은 이걸 그대로 메이븐 의존성으로 옮겨적고 있지요.

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${org.springframework.version}</version>
            <exclusions>
                <!-- Exclude Commons Logging in favor of SLF4j -->
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                 </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${org.slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>${org.slf4j.version}</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${org.slf4j.version}</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.15</version>
            <exclusions>
                <exclusion>
                    <groupId>javax.mail</groupId>
                    <artifactId>mail</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>javax.jms</groupId>
                    <artifactId>jms</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.sun.jdmk</groupId>
                    <artifactId>jmxtools</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.sun.jmx</groupId>
                    <artifactId>jmxri</artifactId>
                </exclusion>
            </exclusions>
            <scope>runtime</scope>
        </dependency>

1번은 단순히 JCL 라이브러리에 의존할 생각이 없기 때문에 빼버리는 것이고, 그때 JCL에 의존하는 클래스들이 깨질 텐데 그것을 JCL-over-SLF4J를 이용해서 겉은 JCL 같지만 내부에서는 SLF4J API를 호출하도록 일종의 어댑터 나 다리 역할을 해주는 라이브러리를 추가하고, 인터페이스 격인 3. SLF4J API를 추가한 뒤 실제 사용할 로거로 SL4J를 구현한 4. SLF4J-Log4J 라이브러리를 추가합니다. 마지막으로 최종적으로 사용할 로거 5. Log4J를 추가한 것입니다. 이때 Log4J가 불필요하게 참조하는 jmx, mail, jms 등의 라이브러리를 제외시켜줍니다.

만약에 Log4J가 아니라 다른 로거를 사용할 거라면 4번과 5번을 교체하면 될테고 JCL 뿐 아니라 log4j에 대한 직접 호출도 slf4j로 오게 하려면 2번 대신 log4j-over-slf4j을 추가하면 되겠습니다.

굉장히 장황니다. @_@;; 하지만 뭐.. 좋다는데.. 갈아타긴 해야겠죠.

출처: SLF4J in 10 slides, by Ceki Gülcü

위와 같은 설정은 스프링 3.0 예제와 레퍼런스에서 사용하고 있습니다. 정말 장황합니다. 일단 여기서 1, 2번은 필수다 하지만 레퍼런스와 블로그 글에도 나와있듯이 그 이하 3, 4, 5는 Logback이라는 SLF4J API 구현체로 한방 설정이 가능합니다.

logback은 크게 세 가지 모듈로 나뉘는데 그 중에 SLF4J API 구현체인 classic 모듈이 있고, Log4J를 개선한 core 모듈이 있습니다. logback 모듈을 가져오면 위에서처럼 log4j가 끌고오는 부가적인 라이브러리도 없고 깔끔하게 log4j API를 사용할 수 있습니다.

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${org.springframework.version}</version>
            <exclusions>
                <!-- Exclude Commons Logging in favor of SLF4j -->
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                 </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>${org.slf4j.version}</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>com.springsource.ch.qos.logback.classic</artifactId>
            <version>0.9.9</version>
        </dependency>

따라서 굳이 Log4J가 아닌 다른 로거로 갈아탈 계획이 없다면 이렇게만 설정해도 되겠습니다. 로깅 설정만 거의 1/3로 줄어듭니다.

사용법은

1. SLF4J API를 이용해서 로거를 만들고..

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Logger log = LoggerFactory.getLogger(AccountJsonBindingTests.class);

2. 다음과 같이 로깅하면 됩니다.

log.info("name is {}", name);

+를 사용해서 문자열 연산을 할 필요도 없고, if문을 줘서 문자열 연산을 막을 필요도 없습니다.

3. log4j 설정은 프로퍼티 파일이나 XML로 할 수 있는데 스프링 3.0 예제는 보통 XML을 사용하더군요. src와 test 소스 폴더 하위의 클래스패스 루트에 각각 다음과 같은 log4j.xml 파일을 둡니다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//LOGGER" "log4j.dtd">

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

    <!-- Appenders -->
    <appender name="console" class="org.apache.log4j.ConsoleAppender">
        <param name="Target" value="System.out" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%-5p: %c - %m%n" />
        </layout>
    </appender>

    <!-- 3rdparty Loggers -->
    <logger name="org.springframework.core">
        <level value="info" />
    </logger>

    <logger name="org.springframework.beans">
        <level value="info" />
    </logger>
   
    <logger name="org.springframework.context">
        <level value="info" />
    </logger>

    <logger name="org.springframework.web">
        <level value="info" />
    </logger>

    <!-- Root Logger -->
    <root>
        <priority value="warn" />
        <appender-ref ref="console" />
    </root>
   
</log4j:configuration>

src와 test 간의 차이는 마지막 부분의 <root> 안의 <priority>가 src에서는 warn이고 test에서는 info라는 것 뿐이 없습니다. 이 설정에서는 Log4J를 사용하고 있는데.. logback API를 이용해서 설정해도 당근 잘 동작합니다.

top

  1. Favicon of http://www.timberlandbaratas.com BlogIcon botas timberland 2012.12.25 14:47 PERM. MOD/DEL REPLY

    La ville de Lille a été condamnée jeudi à indemniser une famille après la disparition d'une tombe dans un cimetière géré par la commune, http://www.timberlandbaratas.com timberland, a-t-on appris auprès de l'avocat des descendants du défunt, http://www.timberlandbaratas.com Timberland. France Amara appelée à se prononcer sur la "censure" d'un rapport de l'Igas France Un gar, http://www.timberlandbaratas.com Hombre Timberland?on de 17 ans mis en examen pour viol sur une fille de 12 ansRelated articles:


    http://unitedkorea.tistory.com/216 Le syndicat Sud-PTT a affirmé mercredi que la Poste avait supprimé 13

    http://persone.tistory.com/46 Terra Nova

Write a comment.


자바 System.out.println 콘솔 출력 가로채기

Java : 2010.01.25 16:49


public class Sout {

    public void hi(){
        System.out.println("hi");
    }

}

이렇게 콘솔에 어떤 메시지를 출력하는 경우가 있을 때 저걸 애플리케이션에서 캡춰할 수 있는 걸 만들어 보는 과제가 떨어졌다.

public class SoutTest {

    SoutInterceptor soutInterceptor = new SoutInterceptor();

    @Test
    public void sout() throws IOException {
        soutInterceptor.active();

        Sout sout = new Sout();
       sout.hi();

        assertThat(soutInterceptor.getMessages(), is("hi"));
    }

}

간단하게 테스트를 만들고 돌려보기 시작했다. 캡춰한 메시지를 어떻게 가져올지가 고민이었는데 그냥 생각난 가장 단순한 방법으로 가져오게했다. 이제 남은건 SoutInterceptor라는 녀석을 만드는 일이다. 뭘 어찌해야 한담 @_@;

가장 먼저 떠오른 방법은 콘솔을 모니터링 하는것이다. 그런데.. 넘 복잡할 것같고 막연하다. 다음으로 떠오른게 AOP. out.println()을 할 때 가로챌 수 있지 않을까? 하지만 힌트가 전달됐다. out을 교체할 수 있단다. 크헉.. 이건 뭐 거의 정답 수준의 힌트이지만 그렇게 간단하지는 않다고 한다. 좋아 해보자.

코딩은 구글신과 함께.. (또는 사부님 말씀대로 이클립스 코드를 뒤지면 나올지도 모른다. 사부님은 이미 뒤져본 것 같다. 자신이 생각한 방법과 동일한 방법을 사용했다고 한다. 어떤 건지는 안 찾아봐서 모르겠다;; 수천 수만 개나 되는 소스 코드를 받아오기도 귀찮고 그걸 IDE에 로딩하는데 엄청 오래 걸릴 것이며 잘못해서 뻑나거나 빌드가 안되고 컴파일 에러잡고 그러면서 삼천포로 가고 싶진 않았다.)

public class SoutInterceptor {

    private PipedInputStream pipedInputStream;
    private PrintStream originalPrint;

    public SoutInterceptor() {
        originalPrint = System.out;
        this.pipedInputStream = new PipedInputStream();
    }

    public String getMessages() throws IOException {
        byte[] messages = new byte[pipedInputStream.available()];
        pipedInputStream.read(messages, 0, messages.length);
        return new String(messages);
    }

    public void active() throws IOException {
        final PipedOutputStream pipedOutputStream = new PipedOutputStream(pipedInputStream);
        PrintStream saveStream = new PrintStream(pipedOutputStream) {
            @Override
            public void println(String x) {
                try {
                    pipedOutputStream.write(x.getBytes());
                } catch (IOException e) {
                    System.out.println("error");
                }
                originalPrint.println(x);
            }
        };
        System.setOut(saveStream);
    }

}

오호.. 잘 돌아간다.. +_+.

테스트를 좀 더 해보자.

        sout.hello();
       
        assertThat(soutInterceptor.getMessages(), is("hello"));

아래에 이렇게 추가하고 hello() 메서드 안에서는 hello를 출력하게 했다. 또 테스트가 잘 돌아간다. 흠.. 이제 맞게 한건가?

println(Stirng x)를 재정의 했는데 print(int), println(boolean) 를 호출할 때도 잘 동작한다. 왜그럴까?

top

  1. Favicon of http://toby.epril.com BlogIcon 토비 2010.01.25 21:15 PERM. MOD/DEL REPLY

    넘 배낀티가...

    기선 2010.01.26 08:21 PERM MOD/DEL

    검색하니까 자바 API 문서밖에;;@_@;

  2. Favicon of http://lf.hisfy.com/ BlogIcon 엽우 2010.01.26 01:36 PERM. MOD/DEL REPLY

    print(int) 계열 메서드가 내부에서 print(String)을 호출하는 게 아닐까요?

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2010.01.26 17:02 신고 PERM MOD/DEL

    PrintStream 클래스 내부에선 전부 write() 쪽을 호출했던것 같은데 write()는 private이라 재정의할 수가 없더군요

  3. Favicon of http://blog.lckymn.com BlogIcon Kevin 2010.01.26 16:34 PERM. MOD/DEL REPLY

    "println(Stirng x)를 재정의 했는데 print(int), println(boolean) 를 호출할 때도 잘 동작한다. 왜그럴까?"
    정말 잘 동작하나요?ㅡ_ㅡ?
    테스트는 통과할지도 모르지만, 콘솔에는 안 찍힐것 같은데요.
    메세지 가로채는게 되는거는, PrintStream 생성할때 넘기신 PipedOutputStream 때문이겠죠. :)
    JDK쪽 코드를 검토하지는 않았지만, PrintStream 내부의 Writer 등이 새로 만들어 넣으신
    OutputStream을 포함/이용 하는 Wrtier로 생성되어서 그럴껍니다.
    (궁극적으로는 PipedOutputStream 의 write 메소드가 호출될때
    PipedOutputStream 오브젝 생성시 집어넣은 PipedInputStream 에 메세지 내용이 기록되겠죠).
    그럼 굳이 print계열 메소드를 override 하지 않아도 메세지는 가로채지겠죠.
    근데 콘솔에는 아무것도 안 찍히니, print계열 메소드를
    override 해서 원래 있던 System의 PrintStream을 가지고 결과를 찍어주는
    코드를 넣어 줘야겠죠.
    (try-catch블록을 아예 없애고 super.println(x); 로 대체해도 메세지는 가로채집니다만,
    e.g.
    super.println(x);
    originalPrint.println(x);
    println 같이 줄바꿈까지 하는 메소드의 경우는
    가로챈 메세지 뒤에 "\n" 까지 더해지겠죠).

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2010.01.26 17:10 신고 PERM MOD/DEL

    앗.. 그렇군요. PrintStream이 바뀌면서 그 안의 Writer가 아얘 바뀐거로군요.

    확인해본 결과 Kevin님께서 말씀해주신것처럼 동작했습니다. println(Stinrg)으로 호출한 것만 콘솔에 찍히더라구요.

    흐흣.. 감사합니다. :)

  4. J.U. 2012.06.08 01:51 PERM. MOD/DEL REPLY

    프로그래밍 중 콘솔 출력 메시지를 가로채올 일이 있었는데, 포스팅이 정말 큰 도움이 되었습니다. 감사합니다!!

Write a comment.


차량 블랙박스 꼭 다세요;

모하니?/Watching : 2010.01.21 14:20




차량으로 높이뛰기 자해공갈자



후진 부부 사기단

세상이 흉흉하네요. @_@;; 저는 차가 없지만 아내가 임신하게되면 차를 리스할까 생각중이긴 합니다.
top

Write a comment.


[봄싹 DevTerms] 활성화 맞춤형 개발

모하니?/Coding : 2010.01.21 10:15



현재 봄싹 DevTerms는 오픈을 한지 얼마 안되서 인지 사용자가 몇 안되고 쌓인 데이터가 별로 없지만 장차 사용자도 늘어나고 데이터가 많아지면 다음과 같은 기능을 추가할 계획입니다. (어제 오늘 오픈 하고 난 뒤 생간난 아이디어들입니다.)

봄싹 DevTerms 트위터가 활성화 되면..
- 개발 용어 및 한글 용어가 올라갈 떄마다 트위터에 등록되는데, 만약 봄싹 DevTerms 트위터가 활성화 되어 올라온 메시지에 누군가 reply나 retweet등을 달면 해당 메시지들을 읽어와서 봄싹 DevTerms에서 보여줄 수 있겠습니다.

개발 용어가 많이 등록되면..
- 오늘 용어, 이번주 용어 탭을 추가하여 오늘 하루에 몇 개나 등록됐으며 어떤 단어들이 등록됐는지 볼 수 있게 하겠습니다. 그러나.. 아직은 뭐..

등록된 개발 용어가 2000개가 넘으면...
- 아이폰과 안드로이드폰 용 애플리케이션을 개발하겠습니다.

개발 용어가 빈번히 등록 또는 수정 된다면..
- 코멧을 적용하여 트위터처럼 실시간으로 새로 등록된 용어가 있음을 알려주고 페이지 업데이트를 하라는 메시지를 전달하거나 자동으로 페이지를 업데이트 해주겠습니다. 리버스 Ajax를 적용해야되서 기술적으로도 재밌을 것 같네요.

등록자 외에도 개발 용어를 편집하고 싶은 분들이 있다면..
- 위키 형태로 히스토리를 저장하고 누가 언제 수정했는지 기록을 남기겠습니다. 현재는 관리자 권한을 가진 사용자는 모든 용어를 편집할 수 있지만 히스토리를 남기고 있지 않아서 위키라고 볼 수는 없는데 아직 이 기능이 필요한 시점은 아닌 것 같습니다. 활성화가 된다면 모를까..

뷰 카운트 및 추천 카운트가 1000이 넘는다면..
- 현재 봄싹 막내(스루)가 미래를 위한 대비 작업으로 천천히 진행 중이긴 한데, StackOverFlow 처럼 카운트 단위를 도입해서 1000건이 넘는 조회수에는 k를 붙여서 1000v -> 1kv로 카운트 단위를 적용하겠습니다.

The more you use it, the more you will get.



top

Write a comment.


2010 대한민국 매쉬업 참가했습니다.

모하니?/Coding : 2010.01.20 16:30


"개발 용어 한글화 프로젝트 DevTerms"로 참가했습니다. 이 녀석을 어제 배포하고 밤새 나머지 주요 기능 중 하나였던 '관심 용어'까지 구현한 뒤 배포하고 참가 신청까지 완료했습니다. 2010 매쉬업 참가 목록에서 보실 수 있습니다.


위에 보시면 아시겠지만 작년 11월부터 이미 DevTerms를 만들고 싶다는 이야기를 봄싹 그룹스에서 했었습니다. 그러던 중 매쉬업 소식을 듣게 되었고 DevTerms에 오픈 API를 적용해서 내보내게 된 겁니다. 1석 2조가 됐지요. 어차피 봄싹에 새 기능으로 추가할 계획이었고 그 기능에 필요한 오픈 API를 적용해서 매쉬업까지 나갔으니 말이죠.

그래서 그런지 제가 제출한 제품은 매쉬업이 메인이 아니라 '개발 용어 한글화' 서비스가 메인입니다. (벌써 43개나 제출됐네요.. 캬오.)그걸 보조하는 수단으로 사전 API와 트위터 API 사용하고 있죠. 사전 API는 기대 했던 것 보다 효과가 좋다고 생각하고 있습니다. 개발 용어는 영어 사전으로 검색한 결과를 보여주고 한글 용어는 한글 사전으로 검색한 결과를 보여주고 있습니다. 트위터 API를 이용하여 등록되는 용어들을 트위터 메시지로 등록해주고 링크를 타고 봄싹 DevTerms로 올 수 있게 해뒀습니다. 트위터 서비스만 해두면 사용자들이 트위터 RSS 피드나 노티 애플리케이션을 이용해서 등록되는 용어들을 실시간으로 받아 볼 수도 있지요.

http://twitter.com/devterms

사실 중간에 매쉬업 참가를 포기할까도 고민했습니다. 혼자서 디자인까지 신경쓰면서 기능 구현을 하자니 중간에 탁탁 끊기는 느낌이고 누군가 제가 집중해서 기능을 구현하고 있으면 그 동안 만든 페이지들 디자인을 점검하고 개선해주면 좋겠다 싶어서 봄싹 팀원에게 도움을 요청했습니다. 다행히 그 친구가 흔쾌히 승낙하고 휴가까지 반납하고 우리 회사로 찾아와 개발을 해주었기 때문에 일정과 품질을 다 기대했던 것 만큼 맞출 수 있었다고 생각합니다. 회사나 계약 등으로 묶여서 같이 일하는 것이 아니라 순수한 열정으로 묶여서 '함께 일한다'는 것이 무엇인지 조금은 알 수 있을 것 같은 기분입니다.

개발에 투자한 일수는 얼마 되지 않습니다. 1월 초까지도 번역을 하고 있었고 JSF를 공부하던 중에 갑자기 매쉬업이 생각나서 저번주부터 오늘까지 한 10일 정도 달린 것 같습니다. 하지만 투자한 시간은 거의 한달 정도 회사일에 투자한는 시간이었던 것 같습니다. 아침 10시부터 새벽 5시까지 전철 타고 밥먹는 시간 뺴고 코딩만 해본건 처음이었습니다. @_@ (어제와 오늘은 출근 길에도 전철에서 코딩을 했습니다. 아흑.. '쟤 모야... '이런 사람들의 시선도 무시한 채 꾿꾿히..) 이렇게 빠져버린 날 이해해준 아내에게 그저 고맙고 미안할 뿐입니다.

원래 계획은 1월 20일. 오늘부터 다시 번역에 집중해서 2월 달 안에 번역을 마무리하는게 계획이었습니다. 그런데 왠걸.. 24일까지 수정할 수 있게 해준다는군요. 뭐 기존에 생각했던 기능들은 다 만들었지만 막상 써보니까 생기는 요구사항들을 무시할 순 없을 것 같습니다. 24일까지만 손을 대고 후딱 번역을 마무리 한 다음 3월부터 진정한 2010년을 맞이해야겠습니다. 후아...

결과가 어찌될지 몰겠지만 수고했다. 기선아. 조금만 더 하고 마무리하자.





top

  1. Favicon of http://helols.pe.kr BlogIcon is윤군 2010.01.20 23:29 PERM. MOD/DEL REPLY

    완전 고생했어요 ^^

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2010.01.21 10:18 신고 PERM MOD/DEL

    응. 과정은 괜찮았는데.. 대중적인 서비스가 아니라서 결과는 어떨지 몰겠다.

    너네 팀은 결과도 좋을 것 같은 예감이야. 치얼업!

  2. Favicon of http://blog.outsider.ne.kr BlogIcon Outsider 2010.01.21 17:51 PERM. MOD/DEL REPLY

    데브텀즈를 만들고 있다는 것을 안지 얼마 안되긴 했는데....
    차곡차곡 데이터 누적되면 여러모로 유용할 듯.. ㅎㅎㅎ
    고생많았어~~ ㅎㅎㅎㅎ

    기선 2010.01.21 22:14 PERM MOD/DEL

    봄 데탑도 완전 멋져요. 저는 엄두도 못낼 작품인데;; 대단하세요. +_+

  3. astre 2010.01.21 19:46 PERM. MOD/DEL REPLY

    남편아 수고했어염!! 좋은 결과 있음 좋겠는데..
    나도 좋은 결과 있을꺼야~! ㅋㅋㅋ

    기선 2010.01.21 22:15 PERM MOD/DEL

    응 난 겨우 8대 1일지만 자기는 30대 1.. 잘 되겠지.

  4. 창천 2010.01.22 15:14 PERM. MOD/DEL REPLY

    매쉬업대회 홈페이지에 가서 구경해볼께요. 조금만 더 고생하세요. ^^

    Favicon of http://whiteship.me BlogIcon 기선 2010.01.25 10:26 PERM MOD/DEL

    넹. 저번주까지 자잘한 기능을 보완해서 어느정도 작업을 마쳤습니다. 관심 가져주셔서 감사합니다. :)

  5. Favicon of http://mrtint.tistory.com BlogIcon 잇힝유후 2010.01.26 18:16 PERM. MOD/DEL REPLY

    오우.. 멋지군요 ^^ 누가 그런 생각을 했나했는데 기선횽이었군요..

    좋은 결과 있으시길~

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2010.01.27 09:57 신고 PERM MOD/DEL

    오랜만이네;;
    부끄럽게 왜이러시나;; 본선도 못오른 허접때기가지고..

Write a comment.


개발 용어 한글화 프로젝트 "DevTerms"

모하니?/Coding : 2010.01.19 19:34


봄싹에서 진행하는 프로젝트 중 하나입니다. 저번 주부터 이녀석 개발하느라 번역도 안하고 회사일도 미루고 잠도 줄이면서 올인했습니다. 아직도 좀 더 만들어야 하는데 일단 사용할 수 있을 정도가 됐다는 판단하에 배포했습니다. (그런데 오판이었어요. 고치고 만들께 아직도 많네요. @_@)

이 프로젝트의 목적은 다음과 같습니다.

- 공동 역자들의 용어 통일화
- 개발 용어에 대한 이해
- 개발 용어 한글화에 대한 근거 확보
- 다수가 선호하는 한글 용어 식별
- 개발 용어 태그 정리

http://springsprout.org/term/index.do



사용해 보시고 의견 주세요~




top

Write a comment.


2장 컴포넌트 식별자와 클라이언트 식별자

JSF/JSF in Action : 2010.01.13 15:21


- UI 컴포넌트는 서버에서는 컴포넌트 트리로 살고 클라이언트쪽에서는 여러 형태의 뷰 표현체로 존재한다.
- 서버쪽에서는 컴포넌트 식별자로 컴포넌트를 참조한다.
- 클라이언트에서는 클라이언트 식별자를 사용해서 컴포넌트를 참조한다.
- 컴포넌트 식별자를 이용해서 클라이언트 식별자를 생성한다.
- 컴포넌트 식별자는 반드시 문자 또는 언더바(_)로 시작한다.
- 컴포넌트 식별자를 생략하면 JSF가 자동으로 만들어 준다.
- Naming container: 하위 컴포넌트들이 모두 유일한 식별자를 가지고 있는 컴포넌트.
- 예를 들어 HtmlDataTable, HtmlForm의 하위 컴포넌트트 식별자에는 이 컴포넌트의 식별자를 이용해서 클라이언트 식별자를 만든다.

top

Write a comment.


대중교통만 타면 짜증나게 만드는 이 더러운 세상!!!!

모하니?/Thinking : 2010.01.12 23:20


아무리 좋은 얘기도 반복해서 들으면 짜증나는데... 아내가 대중교통 이용하면서 짜증나고 시비붙는 얘기를 듣다가 스트레스 폭파 직전이다. 하루 이틀도 아니고..  미치겠다. @_@;;

기존의 MVC 프레임워크가 짜증나면 쓰지 말던가, 새로운 MVC 프레임워크를 만들던가, 이도 정도 아니면 그냥 참고 쓰던가. 셋 중 하나 아닌가?

짜증난다고 시비붙고 욕해봤자 돌아오는 건? 스트레스. 바뀌는 건? 없다. 스트레스는 부부라는 레퍼런스를 타고 나에게 전달되고 아내가 가지고 있던 스트레스도 고대로 위임을 통해 나에게 전달된다. '전달'을 통해서 아내의 스트레스는 어느정도 풀렸는지도 모르겠다. 하지만 나는 이게 왠 봉변이란 말인가? 부부니까 이런것도 받아들여야 하는게 당연한거긴 하겠지만 그래도 나는 비생산적인 스트레스를 전달받고 싶은 마음이 추호도 없다.

피하고 싶으면 피하고, 바꾸고 싶으면 바꿔라. 둘 다 아니면 그냥 참자.

그래도 꼭 '전달'이라는 수단으로 스트레스를 풀어야겠다면 나 말고 다른 사람에게 전달하던지, '여보 영어 공부 좀 더 열심히 해서 우리 빨리 한국을 떠나기로 해요', '여보 내가 빨리 영어 알려줄께' 라고 다소 생산적인 것으로 포장해서 전달해주면 좋겠다.

top

  1. Favicon of http://okjsp.tistory.com BlogIcon kenu 2010.01.13 02:19 PERM. MOD/DEL REPLY

    "비생산적인 스트레스를 전달" <- 기계가 인간이 되기 위해 필요한 자극입니다. 비정형의 인풋을 이해하면 인간이 되는 줄 압니다.
    ^^;
    생산하지 않는 인간도 존재의 의미를 가지고 있습니다.
    그냥 Sync하세요. 그게 부부라 생각합니다.
    행복하세요...

    아,
    하나 생각나는 얘기가 있네요.
    ... 중략 ...
    남편이 다그치자 아내가 ...
    갑자기 울먹이며
    "내가 당신아니면 누구에게 말해?"
    ...

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2010.01.13 10:13 신고 PERM MOD/DEL

    스팸 메시지를 동기화할 필요가 있나 싶기는한데;;
    그렇게 해서 아내맘이 편해진다면;;; 어쩔수 없지요. @_@

  2. Favicon of http://okjsp.tistory.com BlogIcon kenu 2010.01.13 02:21 PERM. MOD/DEL REPLY

    ^^; 그리고 생산적인 해법은 문제의 도메인에서 벗어나는 겁니다.
    차를 사던가... ^^;







    air wolf!!!

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2010.01.13 10:15 신고 PERM MOD/DEL

    사실 차를 산다고 해서 해결될 문제는 아니라고 생각합니다.

    차를 사면 저는 다음과 같은 이야기를 듣게 될껄요.
    "택시 기사가 어쩌구 저쩌구..."
    "앞차가 침뱉고 담배를 던져서 어쩌구 저쩌구.."
    "버스가 .. 블라 블라.."
    "초보가 블라 블라.."
    "라이트도 안키고 블라 블라... "

    뭔가 근본적인 변화가 필요해요.

    쉬운순서대로
    1. 포기하던지
    2. 도망가던지
    3. 개혁하던지

  3. Favicon of http://bluepoetworld.tistory.com/ BlogIcon bluepoet 2010.01.13 09:50 PERM. MOD/DEL REPLY

    정말 서로서로 질서만 잘 지켜도 최소한 짜증만은 나지 않을텐데~

    대중교통 뿐만 아니라, 대중으로 이용하는 모든 것에 해당되는것 같아요.

    힘들고 어렵지만 모두가 노력하는 속에 조금씩 의식을 바꿔가는게

    최선이라고 생각하네요~ 힘네세용^^

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2010.01.13 10:22 신고 PERM MOD/DEL

    글쎄요... 의식이 과연... 좋게 바뀔까요?

    저는 과연 의식 개선을 위해서 어떤 노력을 할 수 있을까요?

    에휴~ 그냥 공부나 하는게 제일 맘편합니다.

  4. nobae 2010.01.13 09:59 PERM. MOD/DEL REPLY

    나에게 전달하면 무진장 싫어하는 내색을 표현하실 필요가 있습니다.
    쪼잔해 보여도 어쩔 수 없습니다. 대탐소실이죠.
    하루 하루 참는 것은 부부금실을 갉아먹는 초석입니다.
    장기적으로 생각하세요.

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2010.01.13 10:25 신고 PERM MOD/DEL

    넹.. 서로 쌓아두는건 없습니다.
    그래서 자주 부딪히고 자주 화해하는 편입니다.

  5. Favicon of http://koko8829.tistory.com BlogIcon 열이아빠 2010.01.13 10:16 PERM. MOD/DEL REPLY

    http://book.naver.com/bookdb/book_detail.nhn?bid=2528148
    이 책을 한번 같이 읽어보세요. 다른 책들도 많이 있지만 쉽고
    현실적인 내용들이 많고 결정적으로 남편이 공대출신이라는....ㄷㄷ
    성격이 다르다는 것은 똑같은 것을 보고도 다르게 인식한다는 것입니다.
    물론 다르다는것을 아는것은 쉽지만 그걸 받아들이고 실천하고 타협하기는 힘들죠.^^

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2010.01.13 10:29 신고 PERM MOD/DEL

    저는 프로그래밍 계열이고 아내는 피아노와 어문 계열이니 비슷하군요. @_@

    MBTI로 성격을 구분하지 않아도 이젠 대충 어떤 성향을 가지고 있는지는 아는데 그에 따른 대책이 들어있나보군요?

    읽어보겠습니다. 감사합니다.

  6. 꾸언 2010.01.15 11:25 PERM. MOD/DEL REPLY

    사실 와이프들의 속풀이는 듣는 입장에서 짜증이조 하지만 짜증으 내섹 냈다간 ^^;;

    후폭풍을 감당하기 힘들껍니다.

    여자들은 특이해서 자기가 하는 말을 들어주는것을 들을 사람이 필요하다고나 할까?

    편한 사람에게 속풀이 하는 습성이 있습니다. ^0^

    기선님이 와이프에게 가장 편하고 좋아한다는 반증이기도 하종 ^^

    힘드시겠지만 잘 들어주세요. 어쩔수 없잖아요 사랑하니깐 털어놓는거니 ^^

    저도 2년째 부부생활을 하지만 당시 저의 처지랑 비슷해서 한자 적어봅니다. ^^

    추운날이 계속되니 몸 건강하세요 기선님 ^-^/

    Favicon of http://whiteship.me BlogIcon 기선 2010.01.15 12:43 PERM MOD/DEL

    제가 좀 철이 없어서;; 생각이 짧았던 것 같습니다.

    앞으론 잘 들어줘야겠어요.

  7. Favicon of http://blog.lckymn.com BlogIcon Kevin 2010.01.17 23:08 PERM. MOD/DEL REPLY

    http://baracuda.tistory.com/1533

    남자가 여자 이해하기 힘들죠.
    여자도 남자 이해하기 힘들구요.

    여자를 이해하려고 하지 마시고,
    남자와 여자의 차이점이 있다는걸 이해하려고 하세요. :)

    그리고 저런 얘기들을 남편 혹은 아내가 안 들어주면 누가 들어주겠어요.
    들어주기 싫으시면 저처럼 솔로가 되는 수밖에... @_@;

    Favicon of http://whiteship.me BlogIcon 기선 2010.01.18 09:56 PERM MOD/DEL

    그러게요;; 제가 좀 예민했었던듯.
    다시생각해보니 저도 사실 스트레스 받으면 이야기 할 곳이 아내밖에 없더라구요.ㅋㅋ

Write a comment.


[스프링 3.0] JSR-330 Provider 인터페이스 이용해서 싱글톤이 아닌 빈을 싱글톤 빈에 주입하기

Spring/3.0 : 2010.01.12 22:26


결국 어디선가는 룩업을 해야합니다. 그냥 주입해서 될 일이 아닙니다. getter injection을 사용할 수도 있지만 AOP, Proxy 등 다소 장황해집니다. 룩업은 하되 가장 표준적이면서, 편리하고, 써드파티 라이브러리 의존성을 낮추는 방법을 얼마전 사부님 블로그를 통해 알게 되었습니다. 그 방법은 바로 구글 쥬스에 있던 걸 표준화 한 JSR-330의 Provider.

먼저 빈 설정입니다. 빈 두개. White는 싱글톤, Ship은 프로토타입 스코프로 설정합니다.

@Configuration
public class ProviderTestAppConfig {

    @Bean White getWhite(){
        return new White();
    }

    @Bean @Scope("prototype") Ship getShip(){
        return new Ship();
    }
}

다음은 위에 등록한 실제 빈 클래스들..

public class Ship {
}

public class White {

    @Autowired
    private Provider<Ship> shipProvider;

    public void hi(){
        System.out.println(shipProvider.get());
    }

}

바로 이 부분이 가장 눈여겨 봐야 할 코드입니다. @Autowired 대신에 @Inject를 써도 됩니다. 그게 중요한게 아니라 스프링이 Provider 인터페이스 구현체를 자동으로 만들어 주입해준다는 것이 중요합니다. 어떤 클래스가 어떻게 해주는지는 귀찮아서 찾아보지 않았습니다. 사부님 책에는 자세한 설명이 나올지도?! +_+

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationContextLoader.class)
public class ProviderTest {

    @Autowired White white;

    @Test
    public void get(){
        white.hi();
        white.hi();
        white.hi();
        white.hi();
    }

}


이건 뭐 기본적으로 자바5는 사용한다는 전제하에 제공되는 것이기 때문에 자바5 도입이 불가능하거나 거부감이 있으신 분들은 스프링의 ObjectFactroy나 ServiceLocatorFactoryBean를 검토해보시는게 좋겠습니다.

ps1: 빈 설정에서 @Scope("prototype")을 때어내도 같은 결과가 나오지 않을까 궁금하다는 생각을 하신 분이 계신가요?? 정답은... 안갈챠드려요. 직접 해보세요. 캬캬캬캬.

ps2: AnnotationContextLoader 이 클래스는 저랑 성윤이가 만든거고 스프링에 없습니다. http://jira.springframework.org/browse/SPR-6567 여기서 소스 및 테스트를 받으실 수 있답니다. vote 좀;;

ps3: 근데 이런 글에 누가 관심이나 있나요.. 싱글톤만 쓰는데;; @_@; 싱글톤이 아닌 빈을 어떻게 왜 써먹는걸까요..? 논의는 봄싹 그룹스에서. 음하핫
top

  1. Favicon of http://toby.epril.com BlogIcon 토비 2010.01.13 19:34 PERM. MOD/DEL REPLY

    초보자 책인데 그런 내용이 나올리가 없자나?

    기선 2010.01.14 09:56 PERM MOD/DEL

    저자 맘이죠.ㅋㅋ

Write a comment.


2장 JSF 요청 처리 생명주기 - Phase 6. 응답 보여주기

JSF/JSF in Action : 2010.01.11 20:58


Render Response

- 최종적으로 사용자에게 응답을 보낸다.
- 뷰 상태를 저장하여 '뷰 복원하기' 단계에서 재사용할 수 있게 한다.
- 특정 뷰 기술에 종속적이지 않다.
- 컨트롤러의 인코딩 메서드 결과만을 뷰에서 사용할 수 있다.
- 컨트롤러의 인코딩 메서드 결과를 마크업을 만드는 애플리케이션에서 통합할 수 있다.
- 컨트롤러의 인코딩 메서드 결과를 정적인 템플릿에 통합할 수 있다.
- 컨트롤러의 디코딩 메서드 결과를 JSP 같은 동적 리소스에 통합할 수 있다.
- 각각의 컨트롤러 인코딩 과정 중에 변환기(Conveter)를 사용하여 컴포넌트의 값을 문자열로 변환한다.
- 이 단계가 JSF 요청 처리 생명주기의 마지막 단계다.
top

Write a comment.


2장 JSF 요청 처리 생명주기 - Phase 5. 애플리케이션 호출하기

JSF/JSF in Action : 2010.01.08 21:49


Invoke Application

- 이 단계에서 등록되어 있는 리스너로 이벤트를 전파한다.
- '요청값 적용하기' 단계에서 만든 액션 이벤트를 여기서 전파한다.
- 컴포넌트에 등록된 액션 리스너 EL을 평가하여 백빈의 특정 메서드(액션 리스너 메서드)를 실행한다.
- 액션 리스너 메서드는 컴포넌트의 actionListener 속성으로 설정한다.
- 액션 리스너 메서드 실행이 끝나면 모든 컴포넌트에 자동으로 등록되는 기본 리스너를 실행한다.
- 기본 리스너는 컴포넌트에 등록되어 있는 액션 메서드를 호출한 뒤 해당 메서드의 논리적인 이름을 통해 랜더링할 뷰를 찾는다.
- 액션 메서드는 컴포넌트의 action 속성을 설정한다.
- 액션 메서드가 없는 경우 기본 액션 리스너가 현재뷰를 랜더링 한다.
- 액션 리스너 메서드나, 액션 메서드에서는 직접 응답을 랜더링 할 수도 있고, 애플리케이션 메시지를 추가할 수도 있고, 이벤트를 만들 수도 있고, 애플리케이션 로직을 실행할 수도 있고, 그냥 뷰 랜더링 단계로 건너뛸 수도 있다.
- 모든 리스너 실행이 끝나면 뷰를 랜더링 할 준비가 된 것이다.


top

Write a comment.


새해 선물 또치



아내가 선물해준 신년 선물 또치.
이쁘구나!
근데 요즘 말썽을 부려서 원;;;

01


아침에 일어나서 제일 먼저하는 일이 이녀석 똥/오줌을 치우는 일이라는 @_@;;
top

TAG 또치
  1. Favicon of https://dazzilove2.tistory.com BlogIcon dazzi 2010.01.09 16:07 신고 PERM. MOD/DEL REPLY

    ㅋㅋㅋ. 아침, 저녁으로 치워야 하는 상황이 될걸요.
    그마나 한 마리라서 다행이네.. ㅎㅎㅎ

    Favicon of http://whiteship.me BlogIcon 2010.01.10 15:11 PERM MOD/DEL

    아 맞다; 누나넨 세마리인가 그랬죠;;
    임신도 하셨는데 아직도 키우고 계세요??;;
    애 나오면 어쩌려구요;;;

Write a comment.


2장 JSF 요청 처리 생명주기 - Phase 4. 모델 값 변경하기

JSF/JSF in Action : 2010.01.07 20:38


Update Model Values

- JSF EL 표현식을 통해서 모델 또는 백빈의 속성 값을 설정한다.

<h:inputText id="helloInput" value="#{helloBean.numControls}" 
             required="true"> 
... 
</h:inputText> 

1. helloBean이라는 키를 가지고 있는 빈을 찾아온다.
2. helloBean의 numControls 속성에 값을 해당 컴포넌트의 로컬 값으로 설정한다.

- 이 단계가 끝나면 관련 리스너에 이벤트를 보내고, 여태까지 그랬던것처럼 리스너에서는 응답을 직접 출력하거나  Render Response 단계로 건너뛸수도 있다.



top

Write a comment.


2장 JSF 요청 처리 생명주기 - Phase 3. 검증하기

JSF/JSF in Action : 2010.01.07 20:26


Process Validation

- 이 단계에서 JSF는 컴포넌트 트리를 순회하면서 각각의 컴포넌트에게 자신의 값을 수용할 수 있는지 확인하도록 요청한다.
- '요청 값 적용하기' 단계에서 입력 컴포넌트들이 갱신되기 때문에 이 단게에서는 사용자가 입력한 최신값을 가지고 있다.
- 검증을 하기전에 변환기에 의해 값이 변환된다.
- 변환기와 검증기를 무사히 거치고 나면 해당 값을 서브밋하고 다음 단계로 넘어간다.
- 그렇치 않은 경우 '응답 보여주기' 단계로 넘어간다.

<h:inputText id="helloInput" value="#{helloBean.numControls}" 
             required="true"> 
<f:validateLongRange minimum="1" maximum="500"/> 
</h:inputText> 

1. required 속성이 true가 입력한 값이 있는지 검사한다.
2. 컨버터가 입력한 값을 int로 바꾼다.
3. validateLongRange 검증기가 값의 범위를 검증한다.

- submitted value가 변환과 검증이 끝나면 그 값을 기반으로 로컬 값을 세팅하는데 이때 value change event가 발생하고 그에 따른 적절한 리스너가 실행된다. 이 리스너들에 의해 직접 응답을 출력하거나 Render Repsponse 단계로 넘어갈 수 있다.
- 모든 submitted value가 유효하다면 다음 단계로 넘어간다.


top

Write a comment.


2장 JSF 요청 처리 생명주기 - Phase 2. 요청 값 적용하기

JSF/JSF in Action : 2010.01.06 20:42


Apply Request Values

- 사용자 입력을 받는 컴포넌트들은 사용자가 입력한 원래 데이터를 나타내는 submitted value를 가지고 있다.
- 프레임워크가 요청의 매개변수를 기반으로 submitted value를 설정해준다.
- 이 과정을 decoding이라 부른다.
- 각 컴포넌트는 자신의 id와 자신을 감싸고 있는 컴포넌트의 id를 이용해서 client identifiter를 만든다.
- 이 단계에서 컴포넌트의 요청에 자신의 client id에 해당하는 매개변수가 있는지 확인하여 있다면 그 매개변수의 값으로 설정한다.
- 컴포넌트의 immediate 속성을 true로 설정하면 검증 단계에서 하지않고 그 즉시 검증을 실행한다.
- 이 단계에서 액션 이벤트를 만들 수도 있다. 만들어진 이벤트는 FacesContext에 추가되고 나중에 '애플리케이션 호출' 단계에서 사용된다.
- 이 단계가 끝난뒤 존재하는 이벤트를 관련 리스너로 전달한다.
- 모든 랜더러, 컴포넌트, 리스너는 생명주기를 단축시켜 이 단계를 건너뛰거나 바로 최종단계로 넘어갈 수도 있다.
- 또는 각각의 입력 컴포넌트가 적절하게 디코딩된 속성을 가지고 현재 요청에 기반한 최신 값을 가지고 있을 것이다.



top

Write a comment.


2장 JSF 요청 처리 생명주기 - Phase 1. 뷰 복원하기

JSF/JSF in Action : 2010.01.05 21:37


Restore View

- 뷰는 특정 페이지를 구성하는 모든 컴포넌트를 나타낸다. 
- 브라우저 위에 히든 필드를 이용해서 클라이언트에 저장될 수도 있고, 세션을 이용해서 서버에 저장될 수도 있다. 서버에 저장되는게 기본값이다.
- 각각의 뷰는 컴포넌트 트리로 구성되며 고유의 식별자를 가지고 있다. 그 식별자를 "뷰 식별자"라고 한다. View identifier
- 뷰 식별자는 요청에서 특수한 경로에 해당한다. 서블릿 경로 이후의 값이 뷰 식별자가 된다. 예) http://spirngsprout.org/study/35.do 에서 /study/35.do
- 폼을 보여준 페이지와 동일한 페이지로 다시 포스팅 요청을 하는 것을 포스트백(postback)이라고 한다.
- 기존의 프레임워크와 차이: "이 액션을 수행하라." VS "사용자가 이 명령을 실행했다.", "사용자가 이 컨트롤의 값을 변경했다."
- 이때 중요한 것은 최종 페이지가 어떤 것이며, 그곳에서 어떤 이벤트가 발생했는냐 이다.
- 현재 뷰를 찾아서 사용자가 입력한 내용을 거기에 적용하는 것이 이 단계의 주요 작업 중 하나이다. 
- 세션에서 뷰를 찾아 본 뒤에 뷰가 있으면 그것을 가져와서 FacesContext에 저장하고, 없으면 새로 요청한 뷰 식별자를 기반으로 새로운 뷰를 만들어서 FacesContext에 저장한다.
- 뷰를 복원하는 단계에서 컴포넌트의 값은 물론이고 그와 관련된 이벤트 리스너, 검증기, 변환기도 복원됐는지 확인한다.
- 백빈의 속성에 바인딩되어 있는 컴포넌트의 경우에는 이 단계에서 백빈의 속성과 컴포넌트가 동기화된다.
- 브라우저가 보낸 HTTP 요청의 헤더를 통해 뷰에 사용할 언어를 설정한다.
- 요청이 포스트백일 경우에는 다음 단계로 넘어가고, 그외의 경우에는 처리할 사용자 입력이 없기 때문에 응답 랜더링(Render Response) 단계로 넘어간다.

 
top

Write a comment.


시베리안 시츄 - 또치



012


시베리안 애완 암컷 시츄.. 또치야.. 니가 고생이 많다.
top

TAG 또치, 시츄
  1. Favicon of http://2-up.tistory.com BlogIcon HyunJun.K 2010.01.08 04:35 PERM. MOD/DEL REPLY

    어린 시츄가 마이 춥겠어요..^^;;;
    어여 따뜻한 안방에 넣어주세요.ㅋ

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2010.01.08 10:26 신고 PERM MOD/DEL

    ㅋㅋ그럼요. 잘 모셔뒀습니다.
    http://whiteship.me/2530

Write a comment.


2장 JSF 기본 - 요청 처리 생명주기

JSF/JSF in Action : 2010.01.04 18:11


뷰 복원하기(restore view) - 선택한 뷰에대한 컴포넌트 트리를 찾거나 만드는 단계.  HtmlCommandButton 같은 컴포넌트에서 액션 이벤트를 발생 시킨다.

요청 값 적용하기(Apply Request Values) - 컴포넌트의 값들을 요청에 담겨있는 값과 동일하게 맞춘다. 이 과정에서 변환기(Converter)가 사용될 수 있으며,  변환시 에러가 발생하면 변환 에러를 추가한다.

검증 수행(Process Validations) - 모든 컴포넌트가 각자 검증을 수행하도록 지시한다. 검증 에러 메시지가 보고될 수 있다.

모델 값 갱신(Update Model Values) - 컴포넌트에 연결된 백빈(backing bean) 또는 모델 객체의 값을 갱신한다.  변환 에러가 보고 될 수 있다.

애플리케이션 호출(Invoke Application) - 등록된 액션 리스너를 호출한다. 

응답 랜더링(Render Response) - 선택한 뷰를 보여준다.



top

Write a comment.