반응형

Class 파일은 실행 시 Link를 할 수 있도록 Symbolic Reference 만을 가지고 있다.

Runtime 시점에 실제 물리적인 주소로 대체되는 작업인 Dynamic Linking이 일어나게 된다.



Class-File-Format은 Network-Byte-Order 를 사용하기 때문에 Big-Endian 방식을 사용하게 된다.


메모리 주소값을 할당하는 방식을 Network-Byte-Order 를 사용하는데 Big-Endian을 사용하기로 약속되어있고, 서로 다른 계열의 CPU끼리 데이터를 전송받을 때의 문제점을 해결하기 위해 정해진 일종의 약속이다.


  • Gabage-Collector
    • Gabage-Collection을 통해 Heap이나 Method-Area의 사용되지 않는 Object를 Memory에서 삭제한다.
    • HotspotJVM은 Heap을 Young-Generation과 Old-Generation으로 나누어 사용한다.
    • Young-Generation은 Eden영역과 Survivor영역이 존재한다. 객체가 Eden영역으로 처음 Allocation 되며 자주 사용되던 객체가 Old영역으로 가기 전에 Survivor 영역으로 이동하게 된다.
    • Old-Generation은 성숙된 객체들이 Promotion 되는 장소이다.
    • Minor-GC는 Young-Generation에서 발생, Promotion이 발생...
    • Major-GC는 Old-Generation에서 발생, Minor-GC를 통해서 발생할 수도 있음...
    • Full-GC는 너무많은 클래스 로딩으로 Permanent-Area가 부족하게 되어 발생할 수 있음...
    • 잘못하면 suspend-time이 길어져 Stop-The-World 방식의 Compaction으로 회귀할 수 밖에 없음.
  • Gabage-First-Collector
    • Generation 구분을 없애고 Region 으로 재편하였다. 논리적인 구분?
    • 물리적인 Young/Old 영역에서의 Allocation/Promotion 대신 Gabage로만 꽉 차 있는 Region부터 Collection을 시작한다고해서 붙여진 이름이다.
    • G1 Collector는 철저하게 Region 단위로 Gabaga-Collection 이 발생한다. 따라서 Suspend 현상도 Region을 사용하는 Thread에 국한된다.
  • Calss-Loader
    • JVM 안으로 Class를 Load 하고 Link를 통해 적절히 배치하는 일련의 작업을 수행하는 모듈.
    • *.class 파일들을 Runtime-Data-Area 에 적재한다.
    • Bootstrap-Class-Loader(jre/lib/rt.jar), Extention-Class-Loader(jre/lib/ext), Application-Class-Loader(System-Class-Loader, User-Defined-Class-Loader)
    • java5부터 Class-Sharing 제공...
    • Load-Time-Dynamic-Loading과 Runtime-Dynamic-Loading 이 있다...
    • Class-Loader-Work 는 Loading, Linking, Initialization의 세가지 과정이 있다. 클래스파일이 검증을 거쳐 symbolic-reference 가 direct-reference 로 변경되는 과정이다.
  • Executor-Engine
    • Load된 Class의 Bytecode를 실행하는 Runtime-Module이다.
    • 모든 ByteCodes를 Interpreter 방식으로 처리하여 초기의 JVM은 실행속도에 있어서 약점을 가지고 있었는데,  JIT(Just-In-Time) Compiler 방식이 등장하여 문제점을 보완하였다.
    • JIT(Just-In-Time) Compiler 는 Bytecodes 를 NativeCode로 Compile하여 실행시간을 빠르게 하였다. 보통 두 방식을 섞어서 쓴다(Lazy Fashion).
    • loop 와 다차원배열 처리에 성능적으로 약함...


  • Runtime-Data-Area
    • Process로서의 JVM을 수행하기 위해 OS로부터 할당받는 메모리 영역.
    • PC Register, Java Virtual Machine Stacks, Method Area, Heap, Native Method Stacks.
    • PC Register
      • 각 Thread마다 하나씩 존재하며 Thread가 시작할 때 생성된다. Stack-Base로 작동하며 현재 수행중인 JVM 명령어를 가지게 된다.
    • Java Virtual Machine Stacks
      • 각 Thread마다 하나씩 존재하며 Thread가 시작할 때 생성된다. 여러 Stack-Frame들이 있고 현재 수행하고 있는 Method의 정보를 저장하는 것을 Current-Frame 이라고 한다.
      • Stack-Frame은 Local-Variable-Section, Operand-Stack, Frame-Data 세 부분으로 되어 있다.
    • Native Method Stacks
      • 각 Thread마다 하나씩 존재하며 Thread가 시작할 때 생성된다. Native-Code로 호출한 메소드에 대한 Stack 영역.
    • Method Area
      • 모든 Thread들이 공유하는 메모리 영역이다.  JVM이 기동할 때 생성이 되며, Garbage-Collection의 대상이 된다. ClassLoader에게 넘겨받은 ClassFile에서 Type 관련 정보를 추출하여 저장하게 된다. Type-Information, Constant-Pool, Field-Information, Method-Information, Class-Variable, ReferenceToClass-ClassLoader, ReferenceToClass-Class, Method-Table.
    • Heap
      • 모든 Thread들에 의해 공유된다. 메모리 해제는 Gabage-Collection을 통해서 이루어지고, Instance(Object)와 Array객체 두 가지 종류만 저장되는 공간일 뿐이다. 실제 구현에 대해서는 각 벤더에게 위임하였다. HotspotJVM이나 IBM-JVM의 Object-Layout과 Heap 구조를 통해 JVM의 Heap에 대한 전반적인 이해를 하는 것이 의미있을 것이다.

Class와 Instance의 관계

Java 관련 서적을 보면 Class와 Instance를 붕어빵틀과 붕어빵으로 표현하는데, 이것은 좋은 비유라고 생각한다. Class가 Loading 되면 Method-Area 에는 Java로 작성한 Code에서 Class의 속성들을 추철하여 정보화되어 기록된다. 다시 말해 하나의 틀이 만들어지는 셈이다. 이를 테면 이 Class는 이러이러한 Method가 있고 이 내용은 어떠하여 변수는 어떤 것을 가진다는 정보가 MethodArea에서 생성된다.

 만약 누군가가 이 Class에 대한 Instance를 하나 생성하려고 한다면 Method Area의 Class 정보를 틀로 하여 Heap에 Object를 하나 찍어낸다. 이것이 Instance이고 여기에 실제 변수에 대한 실제 메모리 상의 주소 등을 포함하여 사용하게 되는 것이다.

 Member Variable(Instance Variable)의 경우는 Heap에 생성된 Instance에 그 값이 저장되고 Class Variable은 이 Class 정보가 있는 Method Area, 더 정확하게는 Class Variable에 저장된다.


  • Thread...
    • Native Thread 를 White-Thread로 부르고, JVM의 Thread를 Green-Thread라고 부르던 때가 있었다...(JAVA 1.1)
    • JAVA1.2부터 ... 둘이 혼용된 Thread-Model ...
    • JAVA1.3부터 결국엔 Native 가 Default-Thread-Model...
    • GreenThread는 MultiProcessSystem에서 이점을 가질 수 없었다...

Synchronization이 필요한 지역을 Critical-Section이라 하고, Thread가 Critical-Section에 들어가면 반드시 Synchronization 작업을 수행하게 된다. 바꾸어 말하면 Thread 가 Critical-Section에 들어가기 위해서는 Lock을 요청하는 것이고 이 Critical-Section은 Synchronization으로 보호되고 있다고 할 수 있다.


- Object Header에 lock-counter를 통해서 알 수 있다...





반응형
반응형
  • JAVA1
    • Collection이 없어서 Vector, Stack, Hashtable, Properties 가 컬렉션의 명명법을 따르지 않음.
    • Vector, HashTable 클래스들은 동기화처리됨.

  • JAVA1.1
    • Reflection
    • Calendar 

  • JAVA1.2
    • Collection 프레임워크 등장
    • ArrayList, HashMap 클래스들은 동기화처리하지 않고 필요한 경우에만 java.util.Collections 클래스의 동기화 메소드를 이용.

  • JAVA1.3
    • Hotspot-Compiler 내장...(불필요한 컴파일을 회피하고 HotCode에 Optimization을 집중..)
    • Math 의 OS 의존성 때문에 (CPU명령어처리가 다르니까..) StrictMath 가 탄생했다.

  • JAVA1.4
    • CharSequence 가 추가되어 String, StringBuffer 등의 클래스가 구현하였다.

  • JAVA1.5
    • enhanced for-looop
    • Generics 가 추가됨.
    • Iterable 인터페이스 추가.(Collection 인터페이스가 상속받도록 결정)
    • enum(열거형)이 추가됨.
    • Autoboxing 이 추가됨. 기본형과 참조형 사이의 연산이 가능해짐. 
    • Covariant ReturnType(공변반환타입)이 추가되어 Override하는 함수의 반환타입을 SubClass 타입으로 쓸 수 있게 함.
    • 메소드의 매개변수에 동적으로 할당 할 수 있게 가변인자(variable arguments)가 추가되었음.
      • 가변인자는 매개변수 중 제일 마직막에 선언, 내부적으로 배열을 생성하므로 성능을 고민해야 함
    • java.util.concurrent.locks 와 java.util.concurrent.atomic 패키지 추가.
    • String의 contains(CharSequence s), replace(CharSequence old, CharSequence nw)가 추가되었다.
  • JAVA1.6
    • 상수를 선언과 동시에 초기화하지 않아도 되며, 사용하기 전에만 초기화하면 되도록 바뀌었다.

  • JAVA1.7
    • 정수형 리터럴 중간에 '_' under-score를 넣을 수 있게 되었다.
    • 2진 리터럴이 추가되었다. 
    • switch 문 조건식에 문자열이 추가되었다
    • '|' 기호를 이용한 multi-catch 블럭.
    • try-with-resources 가 추가되었음.
      • 보통 입출력관련 클래스들을 사용할 때 close()를 호출하지 않아도 try 블럭을 벗어나는 순간 자동적으로 호출이 된다.
      • AutoClosable 인터페이스를 구현한 클래스여야만 한다.
    • Generics 객체 생성 시 추정가능한 경우 타입을 생략할 수 있다.
      • List<String> list = new ArrayList<>();
    • @SafeVarargs Generics 가변인자에 사용.
    • fork & join 프레임워크가 추가됨.
    • '+'가 포함된 문자열이 parseInt()로 변환가능하게 된 것은 JDK1.7부터이다.

  • JAVA1.8
    • 람다와 스트림.
    • 인터페이스에 default-method와 static-method 가 추가되었다.
    • (지역클래스에서 접근하는 지역변수...)Inner-Class에서 외부클래스의 지역변수는 final을 붙여야 했으나, JAVA8부터 final을 생략할 수 있게 바뀌었다.(대신 컴파일러가 자동으로 붙여준다.)
    • java.time 패키지로 개선된 날짜/시간 제공.
    • java.util.Object 의 hash() 함수의 추가로 Override한 hashCode 구현 지원.
    • @FunctionalInterface 함수형인터페이스 선언.
    • @Native native 메소드에서 참조되는 상수 앞에 붙인다.
    • @Repeatable 어노테이션을 반복해서 적용할 수 있게 한다.

  • ETC
    • JVM이 모든 배열의 길이를 별도로 관리하며 arrayName.length ...
    • array vs arrayList
    • Comparable은 기본적으로 오름차순이기 때문에, Comparator를 구현하여 정렬기준을 바꿀 수 있다.
    • Generics 는 컴파일 시 형변환되어 *.class 파일에는 없는데 주된 이유는 이전 버전 호환을 위해서이다.


반응형
반응형

OIO(Old Input/Output) 와 NIO(Non-blocking Input/Output or New Input/Output) 


 몇 년 사이 두드러진 netty(http://netty.io/) 나 vert.x(http://vertx.io/) 등과 같은 네트워크 라이브러리를 잘 활용하기 위해서는 비동기에 대한 못지 않게 OIO(Old Input Output) 과 NIO(Non-blocking Input Output or New Input Output) 에 대한 개념에 대해 알고 있어야 합니다.


 Java 에서 NIO 는 JDK1.4 에서부터 지원을 하기 시작했는데요. 기존의 Java I/O 는 socket 을 accept() 할 때와, data 를 read() 할 때 해당 Thread 가 Block 이 되는데요. 이런 구조? 때문에 Multi-Thread 를 사용하게 되었으나, 컴퓨터가 처리할 수 없을 정도의 요청이 들어오게 되면 Stack 에 메모리를 할당해야 하는데, 운영체제에 따라 다르지만 보통 64KB 에서 1MB 까지 차지할 수 있다고 합니다. Java는 JVM 을 통해서 많은 수를 처리할 수 있다고 하지만 그럴 경우에는 Context-Switching 에 따른 OverHead 가 크다고 합니다.


Java IO: A classic IO server design - one connection handled by one thread.



 하여튼 Multi-Thread 만으로는 부족하여, polling 과 thread-pool 을 같이 사용하기도 하지만 이또한 완벽한 비동기를 구현하기는 어렵습니다. 그래서 JDK1.4에서는 Non-blocking I/O lib 를 통해서 운영체제 레벨에서 지원되던 것을 Java를 통해서 사용할 수 있도록 했습니다.


Java NIO: A single thread managing multiple connections.


 Java NIO 에 대한 사용을 간단하게 설명하면, Selector 를 생성하여 ServerSocketChannel 에 등록하고 대기상태 없이 Selector의 SelectedSet 에서 ServerSocketChannel 로 들어온 이벤트와 관련된 SelectionKeySet 을 잃어와 이로부터 channel을 구하여 데이터를 처리하게 됩니다. 이 과정에서 Selector 는 Multi-channel 의 작업을 Single-thread 에서 처리할 수 있도록 되어 있는데 이 동작을 Multiplexing 이라 할 수 있습니다. Thread 를 사용하지 않으면서 Thread를 사용하는 효과를 볼 수 있습니다.


Java NIO: Reading data from a channel until all needed datas is in buffer.



 이를 통해, 다수의 클라이언트를 하나 또는 적은 수의 Thread로 처리하게 됨으로써, 메모리 관리와 Context-Switching에 따른 Overhead 가 감소하게 됩니다. 입출력을 처리하지 않을 때는 Thread 를 다른 작업에 활용할 수도 있습니다.




ref) http://tutorials.jenkov.com/java-nio/index.html

ref) http://javacan.tistory.com/entry/87

ref) https://devlearnings.wordpress.com/2010/09/21/tip-use-scheduledexecutor-instead-of-thread-for-polling-or-infinite-loops/

ref) http://www.ibm.com/support/knowledgecenter/SSCRJU_4.0.0/com.ibm.streams.dev.doc/doc/pollingsource.html


반응형
반응형


Interface


 자바에서 간단했던 인터페이스가 JAVA8 의 등장으로 추가된 내용들이 생겼습니다. 항상 쉽게 생각할 수 있지만, 이런 것들이 막상 설명하려면 어렵게 느껴질 때가 있는데요.


 기존의 인터페이스를 간단히 요약하면 다음과 같습니다.


모든 멤버변수는 public static final 이어야 하며 이를 생략할 수 있으며,

모든 메소드는 public abstract 이어야하고 이를 생략 수 있습니다.


이처럼 간단하게만 알고 있었으며 사용하고 있었는데요. 조금 더 자세하게 이야기 해 보도록 하겠습니다.


 자바에서의 인터페이스는 클래스의 bluprint 입니다. 인터페이스는 앞서 이야기 했듯이 static constants 와 abstract methods 로만 이루어져 있습니다. 자바에서의 인터페이스는 완전한 추상화를 만들기 위한 메커니즘입니다. 메소드의 몸체가 없는 자바의 인터페이스는 추상메소드로만 되어 있습니다. 이것이 완전한 추상화를 달성할 수 있게하며 자바에서 다중상속이 이루어지도록 합니다.


 자바의 인터페이스는 또한 IS-A 관계를 표현합니다. 인터페이스는 추상클래스처럼 초기화 될 수 없습니다.


왜 자바의 인터페이스를 사용할까요?


인터페이스를 사용하는 주요한 4가지 이유가 있습니다.

  • 완벽한 추상화를 달성하기 위함입니다.
  • 인터페이스를 사용함으로써, 다중상속의 기능을 지원할 수 있습니다.
  • 인터페이스의 사용은 약한 결합을 이룰 수 있게 합니다.
  • 다형성을 사용할 수 있습니다.

자바 컴파일러는 인터페이스의 메소드 앞에 public 과 abstract 키워드들을 붙이고 멤버변수 앞에 public, static, final 키워드들을 붙입니다.


다른말로, 자연스럽게 인터페이스의 필드들은 public, static 그리고 final 이며 메소드들은 public absctract 입니다.




클래스와 인터페이스 사이의 관계 이해하기.


 아래의 이미지에서 보는 것과 같이, 클래스는 다른 클래스를 extends 하고 인터페이스는 다른 인터페이스를 extends 하지만 클래스는 인터페이스를 implements 합니다.



자바의 인터페이스에 대한 간단한 예제


이 간단한 예제는, 오직 하나의 메소드만을 가지는 Printable 인터페이스이고, 이 구현은 A4 클래스에서 제공되어 집니다.


package com.joochang.test3;


interface Printable {

    void print();

}


public class A4 implements Printable {


    @Override

    public void print() {

        System.out.println("Hello");

    }

    public static void main(String[] args) {

        A4 a4 = new A4();

       a4.print();

    }

} 



인터페이스에 의한 자바에서의 다중 상속.


 만약 한 클래스가 여러 인터페이스들을 implements 한다면, 또는 한 인터페이스가 여러 인터페이스들을 extends 한다면 알려진 것과 같이 다중상속 입니다.



package com.joochang.test3;


interface Printable {

    void print();  

}  

  

interface Showable {

    void show();  

} 


public class A8 implements Printable, Showable {

    public void print() {

        System.out.println("Hello");

    }

    public void show() {

        System.out.println("Welcome");

    }

    public static void main(String args[]){

        A8 obj = new A8();  

        obj.print();

        obj.show();

    }

} 



질문) 다중 상속은 자바에서 클래스를 통해 지원되지 않으나 인터페이스는 가능하다, 왜 그런가?

 여기서 인터페이스를 설명했던 것처럼, 다중상속은 클래스의 경우에 지원되지 않습니다. 그러나 인터페이스는 지원되는데 왜냐하면 구현 클래스에 의한 구현을 할 때 애매모호함이 없습니다.


package com.joochang.test3;


interface MultiInheritance1 {

    void print();  

}  

  

interface MultiInheritance2 {

    void print();  

} 



public class MultiPleInheritance1 implements MultiInheritance1, MultiInheritance2 {


    @Override

    public void print() {

        System.out.println("Hello World!");

    }

    public static void main(String[] args) {

        MultiPleInheritance1 test = new MultiPleInheritance1();

        test.print();

    }

} 


 위에 있는 예제처럼, MultiInheritance1 과 MultiInheritance2 인터페이스는 같은 메소드를 가지고 있지만 그 구현은 MultiPleInheritance1 클래스에 의해서 제공되어 지는데, 그래서 이러한 점에 애매모호함이 없습니다.



인터페이스 상속


클래스는 인터페이스를 implements 하지만 인터페이스는 다른 인터페이스를 extends 합니다.


package com.joochang.test3;


interface MultiInheritance3 {

    void print();  

}  

 

interface MultiInheritance4 extends MultiInheritance3 {

    void show();  

}


public class MultiPleInheritance2 implements MultiInheritance4 {


    @Override

    public void print() {

        System.out.println("Hello World 1 !");

    }

    @Override

    public void show() {

        System.out.println("Hello World 2 !");

    }

    public static void main(String[] args) {

        MultiPleInheritance2 test = new MultiPleInheritance2();

        test.print();

        test.show();

    }

} 


질문) marker 또는 tagged 인터페이스는 무엇인가?


 어떠한 멤버도 없는 인터페이스가 marker 또는 tagged 인터페이스라고 알려져 있습니다. 예를 들면, Serializable, Cloneable, Remote etc. 이것들은 JVM 에게 몇가지 특별한 정보를 제공하기 위해서 사용되어 지는데 그래서 JVM 이 유용한 동작을 수행할 것 입니다.


//How Serializable interface is written?

public interface Serializable{



자바에서의 중첩 인터페이스


Note : 중첩 인터페이스라고 알려진 것과 같이, 인터페이스는 다른 인터페이스를 가질 수 있습니다. 


interface printable{

    void print();

    interface MessagePrintable{

        void msg();

   }



since jdk 1.8  default method in java interface ... 


since jdk 1.8  static method in java interface ...



참고) http://www.javatpoint.com/interface-in-java




반응형
반응형

 Covariant return type 우리 말로 '공변 반환 타입' 이라고 하는데, 리턴 타입은 서브클래스라는 범위 안에서 다양할 수 있다는 것으로 java 1.5 부터 적용 되었습니다. 본래 오버라이딩이 이름이 같아야하고, 매개변수가  같아야 하며, 반환타입 또한 같아야 하는데 java 1.5 부터 Primitive 타입이 아닌 Subclass 타입으로 오버라이딩이 가능하게 된 것 입니다.



refer ) http://www.javatpoint.com/covariant-return-type

          http://www.java-tips.org/covariant-return-types.html


반응형
반응형
1. 정의.
의도
 - 객체 사이에 일 대 다의 의존 관계를 정의해 두어, 어떤 객체의 상태가 변할 때 그 객체에 의존성을 가진 다른 객체들이  그 변화를 통지받고 자동으로 갱신될 수 있게 만듭니다.
위키피디아
 - 옵서버 패턴(observer pattern)은 객체의 상태 변화를 관찰하는 관찰자들, 즉 옵저버들의 목록을 객체에 등록하여 상태 변화가 있을 때마다 메서드 등을 통해 객체가 직접 목록의 각 옵저버에게 통지하도록 하는 디자인 패턴이다. 주로 분산 이벤트 핸들링 시스템을 구현하는 데 사용된다. 발행/구독 모델로 알려져 있기도 하다.
해드퍼스트
 - 옵저버 패턴에서는 한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체들한테 연락이 가고 자동으로 내용이 갱신되는 방식으로 일대다(one to many) 의존성을 정의합니다.

2. 동기
 - 클래스들 사이의 결합성을 낮추기위해(loosely coupled), 게시(publish)-구독(subscribe)과 같은 종류의 관계에 대해서 주체(subject) 와 감시자(observer) 의 형태로 나누어 객체의 상호작용을  표현하기 위함.

3. 활용성
 - 두 가지 형태를 갖는 객체의 상호작용 안에서 어떤 변경에 대해 통보를 받고 변경 되거나 이러한 변경에 대해 다른 객체들이 통보를 받아야 할 때.

4. 참여자
 - subject, observer, concreteSubject, concreteObserver

5. 협력방법
 - ConcreteSubject 는 Observer의 상태와 자신의 상태가 달라지는 변경이 발생할 때마다 감시자에게 통보합니다.
 - subject 의 notify 동작을 통해 등록된 observer 들의 상태를 갱신하도록 합니다.

6. 결과
 - Observer 패턴을 사용하게 되면 주체 및 감시자 모두를 독립적으로 변형하기 쉽습니다.
—Subject 와 Observer 클래스 간에는 추상적인 결합도만이 존재합니다.
— 브로드캐스트 방식의 교류를 가능하게 합니다.
— 예측하지 못한 정보를 갱신합니다.

7. 구현 (고려해야 될 부분)
- Subject 와 그것의 Observer들을 대응시킵니다.
- 하나 이상의 Subject를 감시합니다.
- 누가 Notify 를 촉발시킬 것인가.
- 삭제한 Subject에 대한 Dangling Reference 를 계속 유지할 때가 있습니다.
- 통보 전에 주체의 상태가 자체 일관성을 갖추도록 만들어져야 합니다.
- Observer 별 갱신 프로토콜을 피합니다.(Push Model / Pull Model)
- 자신이 관심있는 변경이 무엇인지 명확하게 지정합니다.
- 복잡한 갱신의 의미 구조를 캡슐화 합니다.
- Subject 와 Observer 클래스를 합칩니다.

8. Diagram




반응형
반응형
1. 정의. 
의도
 - 객체의 내부 상태에 따라 스스로 행동을 변경할 수 있게 허가하는 패턴으로, 이렇게 하면 객체는 마치 자신의 클래스를 바꾸는 것처럼 보입니다.
위키피디아
The state pattern, which closely resembles Strategy Pattern, is a behavioral software design pattern, also known as the objects for states pattern. This pattern is used in computer programming to encapsulate varying behavior for the same object based on its internal state. This can be a cleaner way for an object to change its behavior at runtime without resorting to large monolithic conditional statements[1]:395 and thus improve maintainability.[2] 
해드퍼스트
 - 스테이트 패턴을 이용하면 객체의 내부 상태가 바뀜에 따라서 객체의 행동을 바꿀 수 있습니다. 마치 객체의 클래스가 바뀌는 것과 같은 결과를 얻을 수 있습니다.

2. 동기.
- 한 시스템(책에서는 TCPConnection)의 모든 상태를 표현하는 추상클래스를 통해 각 상태별로 어떻게 동작하는지 관리할 수 있다.
- 상태 조건들이 복잡한 분기문에 숨어 있는 경우 유지보수와 확장에 어려움이 있다.

3. 활용성.
 - 객체의 행동이 상태에 따라 달라지며, 런타임 시에 행동이 바뀌어야 할 때와 다중 분기 조건 처리가 너무 많을 때.

4. 참여자.
 - Context, State, ContcreteState

5. 협력방법.
-  Context 에 있는 State 의 기본 인터페이스를 통해서 Context 클래스에서 현재 상태를 정의하고, 상태에 따라 다른 요청을 받으면 ConcreteState 객체로 전달합니다. 이러한 Context 를 통해 사용자는 State 객체를 직접 다루지 않고 요청을 보내기만 하면 됩니다.

6.결과.
 - 상태에 따른 행동을 국소화하며, 서로 다른 상태에 대한 행동을 별도의 객체로 관리합니다.
 - 상태 전이를 명확하게 만듭니다.
 - 상태 객체는 공유 될 수 있습니다.
 - 동적 상속을 이용하는 방법.

7. 구현(고려해야 될 부분)
 - 누가 상태 전이를 정할 것인가? (Context? State?)
 - 테이블 기반의 대안(다음 상태에 대한 전이 저장) -> Table Driven State  Pattern
 - 상태 객체의 생성과 소멸.

8. Diagram.







반응형
반응형
Decorator Pattern


디자인 카탈로그에는 ...
 - 주어진 상황 및 용도에 따라 어떤 객체에 책임을 덧붙이는 패턴으로, 기능 확장이 필요할 때 서브클래싱 대신 쓸 수 있는 유연한 대안이 될 수 있습니다.
디자인 패턴 영역 - 구조 및 객체 패턴.
디자인 패턴 관계도 - (composite -> adding responsibilities to objects)

의도 - 객체에 동적으로 새로운 책임을 추가할 수 있게 합니다. 기능을 추가하려면, 서브클래스를 생성하는 것보다 융통성 있는  방법을 제공합니다.
* 데코레이터 패턴에서는 객체에 추가적인 요건을 동적으로 첨가한다.
데코레이터는 서브클래스를 만드는 것을 통해서 기능을 유연하게 확장할 수 있는 방법을 제공한다.(상속을 이용해 타입을 맞춘다.)

동기 - 정적인 상속이 아니라 동적인 상황에서 필요할 때-! 객체에 책임을 부여(추가/삭제)하고 싶을 때 사용합니다. 

활용
1. 동적으로 또한 투명하게 다른 객체에 영향을 주지 않고 개개의 객체에 새로운 책임을 추가하기 위해 사용합니다.
2. 제거될 수 있는 책임에 대해 사용합니다.
3. 상속으로 서브클래스를 생성하는 방법이 실질적이지 못할 때 사용합니다.

결과
이익1. 단순한 상속보다 설계의 융통성을 더 많이 증대시킬 수 있습니다.
이익2. 클래스 계통의 상부측 클래스에 많은 기능이 누적되는 상황을 피할 수 있습니다.
부담1. 장식자와 해당 그 장식자의 구성요소가 동일한 것은 아닙니다.
부담2. 장식자를 사용함으로써 작은 규모의 객체들이 많이 생깁니다. 이 때 객체들을 잘 이해하지 못하고 있다면 시스템을 수정하는 과정이 복잡해 진다.

* OCP 를 만족시키는 패턴. 클래스는 확장에 대해서는 열려 있지만 변경에 대해서는 닫혀 있어야 한다.





반응형
반응형
Bridge Pattern

디자인 패턴 카탈로그에는...
 - 구현부의 추상층을 분리하여 각자 독립적으로 변형할 수 있게 하는 패턴입니다.
디자인 패턴 영역 - 구조 및 객체 패턴.
디자인 패턴 관계도 - X.

의도 - 구현에서 추상을 분리하여, 이들을 독립적으로 다양성을 가질 수 있도록 합니다.
* 구현 뿐만 아니라 추상화된 부분까지 변경시켜야 하는 경우에 사용한다.

동기 - 상속대신 추상클래스를 사용하더라도, 추상적 개념을 구현과 분리해서 재사용,수정,확장하기 어려움이 있다. 추상적 개념을 구체적인 구현에 종속적일 필요 없이 생성할 수 있게 해야 한다. (책의 윈도우 컨셉?과 플랫폼이라 표현하고 싶다.)

활용 - 클라이언트가 구현을 모르더라도 구현에 대해 여러 가지 형태를 추상적으로 사용가능하게 한다.
1. 추상적 개념과 이에 대한 구현 사이의 지속적 종속관계를 피하고 싶을 때.
2. 추상적 개념과 구현 모두가 독립적으로 서브클래싱을 통해 확장되어야 할 때.
3. 추상적 개념에 대한 구현 내용을 변경하는 것이 다른 관련 프로그램에 아무런 영향을 주지 않아야 할 때.
4. 사용자들은 사용자에게 구현을 완벽하게 은닉하길 원할 때 (private 을 사용하여).
5. 클래스 상속 계통에서 하나의 이유로 여러 개 클래스가 갑자기 정의되어야 하는 상황일 때.
6. 여러 객체들에 걸쳐구현을 공유하고자 하며, 또 이런 사실을 사용자 쪽에 공개하고 싶지 않을 때.

결과
1.인터페이스와 구현 분리.
2. 확장성 제고. (Abstraction과 Implementor 각자).
3. 구현 세부 사항을 사용자에게서 숨기기.





반응형
반응형


학교 다닐 때 다른 블로그에 등록했던 글 복사 ㅎㅎ - http://blog.naver.com/7dbwnckd/50012727041


널 문자 (='\0')와 널 포인터 (= NULL = (void*)0) 그리고 false 는

사실상 0x00 이라는 같은 값을 가집니다.


하지만 의미상 확연한 차이가 있기 때문에, 다르게 쓰입니다.


# 널 문자

널 문자는 보통, 문자열의 끝을 알리는데 쓰입니다.

char *str = "abcd";

-> [ 'a' | 'b' | 'c' | 'd' | '\0' ]




# 널 포인터

포인터 변수 초기화나 포인터 파라미터 전달 시에 주로 쓰입니다.


// 포인터 변수 초기화
char *pstr = NULL;

// 포인터 파라미터 전달
time_t time(time_t *); // time() 함수 프로토타입

time(NULL);



# 논리값 false

bool 형 변수에 값을 대입하거나, 함수 파라미터 전달 시에 쓰임.

void my_func(bool bExist); // 프로토타입

my_func(false);




모두 같은 값을 가지는 것들이지만...

상황에 따라 쓰이는 경우가 다르지요?


이렇게 의미상 구분이 되는 것들을 나누어 놓지 않으면,

큰 프로그램을 분석할때 아주 골치 아파 진답니다.

반응형
반응형


학교 다닐 때 다른 블로그에 등록했던 글 복사 ㅎㅎ - http://blog.naver.com/7dbwnckd/50013168713


 

standard input으로 쓰이는 scanf .. 이해를 바로 합시다..

 

간단한 예를 하나 들어보죠...

 

바로 아래의 예를 실행시켜 보면... char를 입력하지 못하고 바로 넘어갑니다.

 

void exScanf()
{

 int a;
 char ch;

 printf("enter a number : ");
 scanf("%d", &a);

 

 printf("enter a charac : ");
 scanf("%c", &ch);  

 printf("a: %d , ch: %c \n", a, ch);
}

 

왜냐하면... 첫 번째 입력후 엔터키를 입력하게 되는데요~

그 엔터기가 그 다음 scanf의 문자로 입력되어지는 결과가 나오거든요~

 

그래서 오류를 수정하면... 2가지 방법으로 수정할 수 있답니다.

둘 중 하나를 택일 하시면 됩니다. ^^;;

 

void exScanf()
{

 int a;
 char ch;

 printf("enter a number : ");
 scanf("%d", &a);

 

//  첫 번째 방법...

 fflush(stdin);  // 버퍼를 비워라.

 

 printf("enter a charac : ");

// 두 번째 방법
 scanf("%*c", &ch);  // * wild gey : 앞에 오는 \n 받지마라는 소리.

 printf("a: %d , ch: %c \n", a, ch);
}

반응형
반응형


예전 블로그 복사 - http://blog.daum.net/7dbwnckd/1616504


서버 설정이 잘 되어진다면 다른 설정은 필요가 없어진다.

 

sql 부르는 쿼리태그만 필요할 뿐. ^^;;

 

 <sql:query var="rs" dataSource="jdbc/dbwnckd">
      select host,db from db
 </sql:query>

 

아... 5.5 버전에서 주의할 점이 있다.

 

<taglib>
     <taglib-uri>http://java.sun.com/jstl/core
     </taglib-uri>
     <taglib-location>/WEB-INF/tlds/c-rt.tld
     </taglib-location>
 </taglib>

 

바로~ c.tld 같이 -rt가 아닌 것들은 쓰면 에러남 ㅡㅡ;; jstl버전인갑다.~ 즐하삼~

반응형
반응형


예전 블로그 복사 - http://blog.daum.net/7dbwnckd/4696550


GC(Garbage Colloection)는 언제 발생할까?

1. GC의 원리

 - 메로리 할당

 - 사용 중인 메모리 인식

 - 사용하지 않는 메모리 인식

 

 - JVM의 메모리는 크게 클래스 영역, 자바 스택, 힙, 네이티브 메소드 스택 4개 영역으로 나뉘지만, 가비지 컬렉터가 인식하고 할당하는 자바의 메모리 역역에 대해 공부하자!!(힙)

  Young, Old, Perm(permanent)의 세 영역으로 나누어지는데,

  Young 영역은 Eden, Survivor1, Survivor2

  Old 영역은 메모리영역

 * 일단 메모리에 객체가 생성되면, Eden영역에 객체가 지정된다. Eden영역에 데이터가 어느 정도 쌓이면, 이영역에 있던 객체가 어디론가 옮겨지거나 삭제된다. 이 때 옮겨지는 위치가 Survivor영역이다. 우선순위는 없으며 두 개의 영역 중 한 영역은 반드시 비어 있어야 한다. 그 비어 있는 영역에 Eden 영역에 있던 객체가 할당된다. 할당된 Survivor 영역이 차면, GC가 되면서 Eden 영역에 있는 객체와 꽉 찬 Survivor 영역에 있는 객체가 비어 있는 Survivor 영역으로 이동한다. 그러다가 더 큰 객체가 생성되거나, 더 이상 Young 영역에 공간이 남지 않으면 객체들은 Old 영역으로 이도하게 된다.

 

2. GC의 종류

 - 마이너 GC : Young 영역에서 발생하는 GC

 - 메이저 GC : Old 영역이나 Perm 영역에서 발생하는 GC

 이 두 가지 GC가 어떻게 상호 작용하느냐에 따라서 GC 방식에 차이가 나고, 성능에도 영향을 준다. GC가 발생하거나 객체가 각 영역에서 다른 영역으로 이동할 때 애플리케이션의 병목이 발생하면서 성능에 영향을 주게 된다. 그래서 핫 스팟(Hot Spot) JVM에서는 스레드 로컬 할당 버퍼(TLABs: Thread-Local Allocation Buffers)라는 것을 사용한다  이를 통하여 각 스레드별 메모리 버퍼를 사용하면 다른 스레드에 영향을 주지 않는 메모리 할당 작업이 가능해진다.

 

 

반응형
반응형

오픈 소스 자바 프로젝트를 응용한 웹 어플리케이션개발

-마크 이글(Mark Eagle)


04/07/2004

 자바로 어느 정도 규모의 웹 어플리케이션을 개발하는 일은 보통 일이 아니다. 어플리케이션이 개발될 아키텍처를 만드는 데에는 무수히 많은 고려할 사항이 있기 때문이다. 높은 레벨에서 살펴보면 개발자들은 사용자 인터페이스를 어떻게 제작할 것인지, 비즈니스 로직은 어디쯤에 위치할 것인지, 그리고 어플리케이션 데이터를 어떻게 퍼시스턴스 상태로(물리적 저장 공간에 저장하는 것) 유지할것인지에 대한 결정에 직면하게 된다. 이 각각의 계층들은 그 각자의 계층들만으로도 해결되어야 할 문제들을 가지고 있다. 그것들을 질문으로 표현하면 다음과 같다. 각각의 계층을 연결하는 데 있어 어떤 기술이 사용될 것인가? 변화에 유연하게 대처하기 위하여 어떻게 하면 각각의 계층들간의 결합도를 약하게(원문:loosely coupled) 할 수 있을 것인가? 그 구조가 각각의 계층들에 변화를 주지 않고 특정 계층을 교체할 만큼 유연할 수 있을까? 컨테이너 레벨의 서비스들을 트랜잭션으로 처리하기 위해서는 어떻게 해야 할 것인가?


 당신의 웹 어플리케이션 아키텍쳐를 생성하는 데 있어 나열되어야 할 질문들에는 한도 끝도 없다. 다행히도 그런 과정에 있어 반복적으로 재기되는 문제들의 해결을 위해 일해온 많은 개발자들이 있다. 좋은 프레임웍은 복잡한 문제들에 대한 부품들을 재개발해야하는 문제로부터 개발자들을 좀 더 편안하게 해 준다. 좋은 프레임웍의 요건들은 다음과 같다 : 내부 커스터마이징에 있어 유연해야 한다. 그리고 그 프레임웍을 지원하는 강력한 유저 커뮤니티가 있어야 한다. 각각의 프레임웍들은 일반적으로 한 가지 문제에 대한 효과적인 해결책을 제시해 준다. 그렇지만 당신의 어프리케이션은 그 어플리케이션만의 프레임웍이 필요로하는 여러 층의 계층이 존재한다. 단지 UI 문제를 해결한다는 것은 UI컴포넌트에다 비즈니스 로직과 퍼시스턴스 로직(persistence logic)을 집어넣어 개발하는 것을 의미하는 것은 아니다. 예를 들면,  당신은 JDBC코드를 포함한 비즈니스 로직을 컨트롤러에다 집어넣으면 안되는데, 왜냐하면 이것은 컨트롤러가 제공하려는 기능에 맞지 않기 떄문이다. UI 컨트롤러는 다른 어플리케이션 계층을 UI 계층의 요청으로부터 분리하는 가벼운 컴포넌트로써 그 의미를 가지기 떄문이다. 좋은 프레임웍은 자연스럽게 어떤 코드가 어디에 위치해야하는지의 가이드라인을 형성하게 된다. 더 중요한 점은, 프레임웍은 개발자로 하여금 동일한 패턴의 코드를 계속적으로 제작하는 작업을 줄여 주며 훨씬 더 중요한 어플리케이션 로직 자체에 집중할 수 있는 여유를 준다는 점이다.


 이 글은 약한 결합도(loose coupling)를 가진 아키텍처를 구성하기 위해 잘 알려지 몇몇의 프레임웍을 결합하는 법에 대해 기술하고 있다. 그러기 위하여 어떻게 아키텍처를 설계하는지, 그리고 각각의 어플리케이션 계층간의 디자인을 일관되게 유지하는 방법에 대해 알아볼 것이다. 프리젠테이션 계층에는 스트럿츠(Struts), 비즈니스 계층에는 스프링(Spring), 퍼시스턴스 계층에는 하이버네이트(Hibernate)를 사용할 것이다. 물론 각각의 계층에 사용된 프레임웍을 다른 것으로 교체해서 사용할 수도 있다. 그림 1은 이 프레임웍들이 결합되었을 때 어떤 모양을 이루는지를 보여준다.


Figure 1
그림 1. 스트럿츠, 스프링, 하이버네이트로 구성된 아키텍처의 개략적 구조


어플리케이션 계층화

대부분의 중,대규모 웹 어플리케이션들은 많은 경우에 있어 4개의 계층으로 구성된다 이 계층들은 프리젠테이션, 퍼시스턴스 비즈니스, 도메인 모델(Domain model) 계층들이다. 각각의 계층들은 어플리케이션에서 명확히 구별되는 기능을 가지고 있으며 서로 다른 계층을 침범하거나 그 기능적인 면에 있어 중복되는 점이 없어야 한다. 각각의 어플리케이션 계층들은 다른 계층들과  완전히 분리되어 있지만 각 계층들간의 통신을 위하여 인터페이스를 제공한다. 각각의 계층들을 개괄적으로 훑어보고 각 계층들이 제공해야 할 것이 무엇인지, 제공하지 말아야 할 것이 무엇인지를 알아보자.

프리젠테이션 계층(표현 계층)

Related Reading

Hibernate: A Developer's Notebook

Hibernate: A Developer's Notebook
By James Elliott

일반적인 웹 어플리케이션의 맨 끝에는 프리젠테이션 계층이 존재한다. 많은 자가 개발자들은 스트럿츠가 제공하는 것이 무엇인지 이해하고 있지만 많은 경우에 있어 비즈니스 로직에 관한 코드를 org.apache.struts.Action 클래스를 확장한 Action에다가 같이 집어넣어 구현하는 우를 범하는 것이 사실이다. 그래서 스트럿츠와 같은 프레임웍이 제공해야 할 것이 무엇인지에 대하여 먼저 생각해 보도록 하자. 여기에 스트럿츠가 제공해야 할 것들을 나열해 보았다.

  • 사용자를 위한 request와 response의 처리
  • 비즈니스 로직과 다른 상위 프로세스로의 호출을 웹 환경으로부터 분리하기 위한 컨트롤러 제공
  • 다른 계층(tier)로부터 스트럿츠 액션으로 던져지는 익셉션들을 처리하는 기능
  • 뷰에 표현될 모델들을 논리적으로 엮는 기능
  • UI 검증(UI validation) 수행

보통 스트럿츠를 사용한 계층 안에  같이 코딩되면 안되는 것을 집어넣는 경우가 있다. 그 예들은 다음과 같다.

  • JDBC호출과 같은 데이터베이스와의 직접적인 통신
  • 비즈니스 로직이나 어플리케이션과 관련된 request 검증
  • 트랜잭션 관리

이런 코드들을 프리젠테이션 계층에다 넣는 것은 각 계층들을 복잡하게 엮이게 만들어 유지보수시 성가신 문제를 발생시킨다.

퍼시스턴스 계층(영구 저장 계층)

웹 어플리케이션의 또 다른 끝 계층은 퍼시스턴스 계층이다. 여기서도 흔히 제어권을 벗어난 일들이 발생하는 경우가 있다. 개발자들은  그들 자신만의 퍼시스턴스 프레임웍을 구축하는 데 드는 비용을 경시하는 경향이 있다. 그 상황에 특수화되고 시스템 안에 심어진 퍼시스턴스 계층은 단지 엄청난 개발 시간을 필요로 할 뿐만 아니라 기능도 부족하고 또한 통제 불가능한 상황이 되는 경우가 종종 있다. 이런 많은 문제에 도움이 되는 오픈 소스 객체-관계 맵핑(object-to-relational mapping, 역자주: 자바의 객체를 RDB의 테이블형태로 맵핑시키는 것을 말함))  - ORM - 프레임웍이 다수 있다.  특별히 하이버네이트(Hibernate) 프레임웍은 객체-관계 퍼시스턴스와 자바를 위한 쿼리 서비스를 제공한다. 하이버네이트는 이미 SQL와 JDBC API에 익숙한 자바 개발자들이 익히기에 중간 정도의 노력을 필요로 한다. 하이버네이트 퍼시스턴스 객체(Hibernate persistent objects)는 일반적인 형태의 자바 객체와 자바 콜렉션에 기반을 두고 있다. 게다가 하이버네이트와 흔히들 사용되는 IDE툴을 같이 사용하는 것은 문제가 되지 않는다.  다음에 나열된 것은 퍼시스턴스 프레임웍에 코딩해야할 것들이다.

  • 관계형 정보를 빼내어 객체화 시키는 작업. 하이버네이트는 이것을 HSQL이라 불리는 OO 쿼리를 쓰거나 criteria API를 써서 작업을 수훨하게 한다. HQL은 테이블명 대신에 객체명, 컬럼명 대신에 객체의 필드명을 사용한다는 것만 빼고는 SQL과 아주 유사하다. 몇몇 새로이 익혀야 할 HQL 언어 항목들이 있지만 배우기도 쉽고 HQL 에 관한 문서도 많기 때문에 걱정할 거리가 안 된다.

  • 데이터베이스의 자료를 저장하고, 수정하고, 삭제하는 작업.

  • 하이버네이트와 같은 진보된 객체-관계 맵핑 프레임웍은 대부분의 SQL 데이터베이스를 지원한다. 또한 객체의 부모/자식 관계, 트랜젝션, 상속,  다형성등을 지원한다.

퍼시스턴스 계층에 넣지 말아야 할 것들을 살펴보자.

  • 비즈니스 로직은 더 높은 계층에 포함되어야 한다. 퍼시스턴스 계층엔 단지 데이터 억세스에 관련된 작업만 허용된다..

  • 프리젠테이션 로직과 퍼시스턴스 로직을 뒤섞어서 코딩하면 안 된다. JSP나 서블릿 같은 프리젠테이션 컴포넌트에다 직접적으로 데이터 억세스를 수행하는 코드를 넣지 말아야 한다. 퍼시스턴스 로직을 퍼시스턴스 계층 안에만 한정시킴으로써 어플리케이션은 다른 계층의 변화에 구애받지 않고 퍼시스턴스 계층을 변화시킬 수 있는 유연함을 지니게 된다. 예를 들면 하이버네이트는 다른 계층의 어떤 코드도 바꾸지 않고 다른 퍼시스턴스 프레임웍으로 교체될 수 있다.

비즈니스 계층

일반적인 웹 어플리케이션의 중간 계층에는 비즈니스나 서비스 계층이 존재한다. 코딩에 대한 관점으로 볼 때 이런 서비스 계층은 대부분의 경우에 있어 무시되는 경우가 많다.  비즈니스 계층의 코드들이 UI계층이나 퍼시스턴스 계층에 여기저기 흩어져 있는 어플리케이션을 찾아보기란 그리 어려운 일이 아니다. 이런 구조는 어플리케이션의 시스템이 스파게티처럼 이리저리 뒤섞여 각각의 계층을 모호하게 만들어 유지보수시 많은 시간을 필요로 하게 만든다. 다행히도 이런 문제를 해결하기 위한 몇몇 프레임웍이 있다. 가장 유명한 두가지가 스프링(Spring) 프레임웍과 피코컨테이너(PicoContainer) 프레임웍이다. 이것들은 어떻게 객체들을 엮는지를 결정해주는 조그만 마이크로컨테이너(microcontainer)라고 불리기도 한다. 이런 프레임웍들은 연관성 삽입(dependency injection, inversion of control)이라는 간단한 개념 위에서 동작한다. 이제부터는 스프링 프레임웍에서 빈의 프로퍼티를 동적으로 세팅하는 기능, 즉 설정 파일에서 그 이름을 변경할 수 있는 빈의 프로퍼티의 삽입 기능에 촛점을 맞추어 얘기할 것이다. 스프링은 빈의 setter를 사용한 빈의 프로퍼티 동적 삽입 방식 외에도 생성자를 사용한 방법 또한 지원한다.(역자주: 지금은 무슨 말인지 잘 이해 안가셔도 계속 읽다 보면 이해가 가실 겁니다.^^). 객체들은 트랜잭션 관리자, 객체 Factory, 비즈니스 로직을 담고 있는 서비스 객체, 그리고 퍼시스턴스 계층에 속하는(data access object, DAO) 객체의 레퍼런스를 명시하고 있는 간략한 XML파일에 의하여 그 구조를 형성하게 된다.  그리고 스프링이 사용하고 있는 개념들은 예제를 통하여 훨씬 더 쉽게 알아볼 수 있을 것이다.

그리고 비즈니스 계층은 다음과 같은 요건을 가져야 한다.

  • 어플리케이션 비즈니스 로직 처리와 비즈니스에 관련된 빈의 적합성 검증
  • 트랜잭션 처리
  • 다른 계층들과 통신하기 위한 인터페이스 제공
  • 비즈니스 레벨에 있는 객체들간의 관계를 관리
  • 프리젠테이션 계층과 퍼시스턴스 계층 사이의 다리 역할을 해 그 둘이 직접 통신하지 않도록 함으로써 어플리케이션에 유연성을 더함.
  • 비즈니스 서비스를 얻기 위하여 프리젠테이션 계층으로부터 컨텍스트 객체를 비즈니스 계층으로 넘겨주는 기능
  • 비즈니스 로직과 퍼시스턴스 계층 사이의 실제 구현 관리

도메인 모델 계층

마지막으로 우리는 중대규모의 웹 어플리케이션을 얘기하고 있기 때문에 도메인 객체 계층은 OrderOrderLineItemProduct 객체들과 같은 실제 비즈니스 객체를 표현하게 된다. 이 계층은 개발자가 도메인 객체와 일치시키기 위해 불필요한 데이터 전송용 객체(data transfer objects, DTO) 를 제작하는 것을 막아 준다.  예를 들어 하이버네이트는 데이터베이스의 정보를 도메인 객체에 저장하여 UI 에 표현할 수 있도록 해 준다. 그리고 이 객체들은 수정되거나 하여 다시 퍼시스턴스 계층, 하이버네이트로 돌아와 데이터베이스의 정보를 업데이트하는 데 사용된다.  그리고 여러 계층을 통과하면서 계층들간의 통신시 데이터 전송용 객체(DTO)를 사용하였을 때 발생할 수 있는 데이터의 유실 때문에 데이터 전송용 객체를 사용하지 말 것을 권한다. 이 모델은 자바 개발자들이 별다른 코딩 없이도 객체지향적 방식으로 일할 수 있도록 도와 준다.

간단한 샘플 예제를 통한 각 계층 엮어 보기

이제 고수준 관점에서 각각의 계층을 알아보았으니 실제로 적용해 보도록 하자. 다시 얘기하지만 이 예제에서 스트럿츠, 스프링, 그리고 하이버네이트 프레임웍을 사용할 것이다. 각각의 프레임웍에 대해서 자세히 다루기에는 이 글 하나로는 너무도 부족하고 단지 여기서는 각각의 프레임웍을 어떻게 엮어서 사용하는지를 살펴보기로 한다. 샘플 어플리케이션은 사용자 요청이 각각의 계층을 어떻게 통과하는지를 보여 줄 것이다. 이 샘플 어플리케이션의 사용자는 새로운 주문(Order)를 데이터베이스에 저장하고 이미 데이터베이스에 존재하는 주문(Order)를 살펴보는 기능을 사용하게 될 것이다. 게다가 보강된 버젼에서는 주문(Order)에 대한 수정과 삭제도 지원하게 될 것이다.

이 샘플 어플리케이션의 소스 코드는 여기서 다운받을 수 있다. 

 

샘플 어플리케이션을 제작할 때 우리는 먼저 각각의 계층들이 상호협동하여 동작하기 위해 필요한 도메인 객체들을 생성할 것이다. 이 도메인 객체들은 도대체 어떤 데이터가 DB에 저장될 것인지, 그리고 어떤 비즈니스 로직이 필요할 것인지, 그리고 그 객체들을 보여주기 위해서는 어떠한 화면들이 필요할 것인지를 우리가 정의하는 데 있어 기초가 된다.

다음으로 우리는 퍼시스턴스 계층들 세팅할 것이며 하이버데이트를 통하여 OR 매핑 규칙을 정할 것이다.

그 다음으로는 비즈니스 로직이 포함된 비즈니스 객체를 정의한다.

그 다음으로는 스프링을 사용하여 이 두 개의 계층, 즉 퍼시스턴스 계층과 비즈니스 계층을 역을 것이다.

마지막으로 스트럿츠를 사용하여 프리젠테이션 계층을 생성할 것이다.

도메인 객체 계층(Domain Object Layer)

이 객체들이야말로 각 계층들간을 자유롭게 오가며 상호교류할 수 있게 하는 객체이므로 코딩을 시작하기에 있어 좋은 것들이다. 이 샘플 도메인 모델은 주문(Order)과 주문 항목(OrderLineItem) 객체들로 이루어져 있다. Order객체는 OrderLine객체에 대하여 일대다 관계를 가지고 있다. 예제 코드는 도메인 객체 계층에 대한 간단한 코드를 포함하고 있다.

  • com.meagle.bo.Order.java: 주문에 대한 헤더 정보를 포함
  • com.meagle.bo.OrderLineItem.java: 주문에 대한 자세한 세부정보를 포함

어플리케이션이 어떻게 계층화되어있는지를 알아보기 쉽게 어플리케이션의 페키지 명을 정하는 것이 좋다. 예를 들면 샘플 어플리케이션에서는 도메인 모델 객체들은 com.meagle.bo 패키지 안에 포함되어 있다. 그리고 더 세부화된 도메인 모델 객체들은 아마도 com.meagle.bo 패키지의 서브 패키지로 생성될 패키지 이래에 포함되게 될 것이다. 비즈니스 로직이 포함된 패키지는 com.meagle.service 로 패키지명이 시작되며 DAO 객체들이 포함된 패키지는 com.meagle.service.dao.hibernate 패키지이다. 프리젠테이션 클래스들은  com.meagle.action 과 com.meagle.forms 패키지 아래에 위치하게 된다. 정확한 패키

지 네이밍 룰을 적용하게 되면 각 클래스들이 제공하는 기능들에 대한 명확한 구분이 되며 유지 보수시에 상당한 비용 절감의 효과를 기대할 수 있다.


퍼시스턴스 계층 설정

 하이버네이트를 가지고 퍼시스턴스 계층을 세팅하려면 몇 가지 과정을 거쳐야 한다. 첫 번째 과정은 영구 저장 매체에 저장될 도메인 모델 객체를 설정하는 일이다. 왜냐하면 하이버네이트는 퍼시스턴스 객체로 사용할 도메인 객체로 POJO(Plain, old Java object) 를 사용하기 때문이다. 따라서 Order와 OrderLine객체는 그 객체들의 필드에 대하여 getter와 setter 메소드들을 가진 빈 형태의 객체여야만 한다.  Order객체는 표준 자바빈 스펙의 객체와 같이 ID,UserNameTotal, 그리고 OrderLineItems 프로퍼티에 대한 getter와 setter 메소드들을 가지고 있다.  물론 OrderLine객체 또한 그 객체의 필드들에 대하여 자바빈 스펙을 따른다.

하이버네이트는 도메인 객체를 RDB로 맵핑하는 데 있어서 XML 파일을 사용한다. 우리의 Order와 OrderLineItem 객체에 대하여 각각에 대해 그 맵핑 관계를 설명하는 두 개의 XML파일이 있다. 필요하다면 그 맵핑 XML파일 생성을 도와주는  XDoclet 과 같은 툴을 사용할 수도 있다. 하이버네이트는 도메인 객체 - RDB 맵핑에 있어 다음과 같은 파일을을 사용한다.

  • Order.hbm.xml
  • OrderLineItem.hbm.xml

예제 어플리케이션에서 이렇게 생성된 파일을 WebContent/WEB-INF/classes/com/meagle/bo 디렉토리에서 찾을 수 있다. 하이버네이트 SessionFactory 는 그것이 어떤 데이터베이스와 통신할 것인가, 그리고 어떤 DataSource나 데이터베이스 커넥션 풀을 사용할 것인가, 그리고 퍼시스턴스 대상이 되는 퍼시스턴스 객체들에는 어떤 것들이 있는가를 설정함으로써 설정이 완료된다.  Session 객체는 SessionFactory객체에 의해 생성되는데, 그것은 자바 객체와 퍼시스턴스 계층의 기능들의 호출(selecting, saving, updating, deleting) 사이의 인터페이스를 제공해주는 객체이다. 우리는 뒤에 이어지는 섹션에서 하이버네이트가 Session객체를 생성하기 위해 어떻게 SessionFactory객체를 설정해야 하는지를 살펴볼 것이다.

비즈니스 계층 설정

이제 우리는 어플리케이션 로직을 수행하고 퍼시스턴스 계층의 작업을 수행하고 UI 계층으로부터 request를 받고 트랜젝션 서비스를 적용할 대상 도메인 객체들을 수중에 넣게 되었다.  이것들을 엮는 작업과 차후 관리를 좀 더 편하게 하기 위해서 스프링 프레임웍의 빈 관리 기능을 사용하면 된다. 스프링은 제어 역행화(inversion of control , IoC 역자주 : 마틴 파울러의 '리팩토링' 에 이 패턴에 대한 설명이 나옵니다. 한번 읽어보시는 것도 괜찮을 듯) 나 연관 삽입(setter dependency injection)을 사용하여 외부 XML파일에 기술된 대로 객체들을 엮어 준다. 제어 역행화(Inversion of control)는 어떤 객체로 하여금 더 고수준의 레벨에서 생성되는 객체들을 받아들여 사용하게 할 수 있는 간단한 개념이다. 이런 방법을 사용함으로써 어떤 객체의 인스턴스가 생성되어 사용될 것인지로부터, 그리고 객체들간의 연관성으로부터 객체들이 더 자유로워질 수 있다.

여기에 IoC를 사용치 않아서 객체들간의 연관성이 심화된 상태의 객체 관계에 대한 그림을 예로 들어 보았다.( 역자주: 그림에서 보듯이 객체 A가 B,C를 생성시키므로 A의 구현은 B와 C에 의존하게 됩니다.그림 3과 비교해서 보시면 됩니다.)

Figure 2
그림 2. IoC를 적용하지 않은 객체 관계. 객체 A가 객체 B와 C를 생성시키는 것을 볼 수 있다..

 

그리고 여기에는 고수준 레벨에서 생성된 객체들이 삽입되어 사용될 수 있도록 IoC패턴을 적용한 예제 그림이 있다. 그럼으로써 객체 A는 객체 B와 C의 구현을 직접적으로 사용할 수가 있다.

Figure 3
그림 3. IoC가 적용된 객체 관게. 객체 A는 객체 B와 C의 인터페이스를 받아들이는 setter 매소드를 가지고 있다. 물론 받아들이는 과정은 setter메소드를 통해서뿐만 아니라 객체 A의 생성자를 통해서도 가능하다.

비즈니스 서비스 객체 작성

비즈니스 객체의 setter에 실제 구현 클래스 대신 인터페이스를 사용하는 것은 실제로 구현될 버젼의 클래스를 비즈니스 객체로부터 분리시키는 역할을 한다.  예제에서는 도메인 객체들의 퍼시스턴스 작업을 처리하기 위한 DAO 객체를 서비스 객체가 받아서 처리하도록 할 것이다. 예제에서 다른 퍼시스턴스 프레임웍으로의 전환이 용이한 하이버네이트를 사용할 것이며 퍼시스턴스 프레임웍의 변화에 대해서는 단지 스프링의 설정을 새로운 DAO 객체 구현을 사용하도록 변경하기만 하면 된다. 예제에서 또한 퍼시스턴스 구조로부터 비즈니스 로직을 분리시키기 위하여 인터페이스와 연관성 삽입(dependency injection)을 사용하는 것을 볼 수 있을 것이다.

여기에 DAO객체 연관에 있어 기초가 되는 비즈니스 서비스 객체 코드가 있다.:

public interface IOrderService {
  public abstract Order saveNewOrder(Order order)
    throws OrderException,
           OrderMinimumAmountException;
  public abstract List findOrderByUser(
                                     String user)
                           throws OrderException;
  public abstract Order findOrderById(int id)
                           throws OrderException;
  public abstract void setOrderDAO(
                             IOrderDAO orderDAO);
}

위 예제 코드에 DAO 객체에 대한 setter메소드가 존재함을 주목하라. getOrderDAO 메소드는 없는데 한번 서비스 객체와 결합된 DAO 객체가 외부에서 참조될 일은 없기 때문에 DAO 객체에 대한 getter메소드를 생성하지 않은 것이다. DAO 객체는 우리의 퍼시스턴스 계층과 통신하이 위하여 사용될 것이다. 우리는 스프링을 사용하여 비즈니스 객체와 DAO 객체를 결합시킬 것이다. 그리고 인터페이스를 사용하였기 때문에 실제 구현을 제한되지 않는다.

다음 단계는 DAO 객체에 대한 실제 구현 객체를 작성하는 일이다. Spring은 자체 내장된 하이버네이트 지원 툴을 지니고 있기 때문에 이번 예제에서는 스프링의 하이버네이트 지원 DAO 클래스인 HibernateDaoSupport 를 확장하여 DAO 클래스를 작성하게 된다. HibernateDaoSupport 클래스를 확장하게 되면 HibernateTemplate 객체에 대한 레퍼런스를 얻어서 사용할 수가 있게 된다.   HibernateTemplate객체를 통하면 하이버네이트 세션과 HibernateExceptions을 처리할 수가 있게 된다. 여기에 DAO 객체를 위한 인터페이스가 있다.:

public interface IOrderDAO {
  public abstract Order findOrderById(
                                    final int id);
  public abstract List findOrdersPlaceByUser(
                           final String placedBy);
  public abstract Order saveOrder(
                               final Order order);
}

 아직도 비즈니스 계층을 위하여 결합되어야 할 몇몇개의 클래스들이 남아 있다. 그중에 HibernateSessionFactory 객체와 TransactionManager 객체가 있는데 이것은 스프링 설정 파일을 통하여 비즈니스 계층에 결합될 수가 있다.  스프링은 HibernateTransactionManager 을 제공하여 스레드에 바인드된 하이버네이트 세션의 트랜잭션 기능을 쉽게 사용할 수 있도록 해 준다. (더 자세히 알고 싶으면 ThreadLocal 를 참고하라.). 여기에 HibernateSessionFactory 과HibernateTransactionManager 를 설정하기 위한 Spring 설정 파일의 한 부분이 있다.:

<bean id="mySessionFactory"
       class="org.springframework.orm.hibernate.
              LocalSessionFactoryBean">
  <property name="mappingResources">
    <list>
      <value>
        com/meagle/bo/Order.hbm.xml
      </value>
      <value>
        com/meagle/bo/OrderLineItem.hbm.xml
      </value>
    </list>
  </property>
  <property name="hibernateProperties">
    <props>
      <prop key="hibernate.dialect">
        net.sf.hibernate.dialect.MySQLDialect
      </prop>
      <prop key="hibernate.show_sql">
        false
      </prop>
      <prop key="hibernate.proxool.xml">
        C:/MyWebApps/.../WEB-INF/proxool.xml
      </prop>
      <prop key="hibernate.proxool.pool_alias">
          spring
      </prop>
    </props>
  </property>
</bean>
<!-- 단지 Hibernate SessionFactory 만 사용할 때의 트랜잭션 매니져  -->
<bean id="myTransactionManager"
         class="org.
                springframework.
                orm.
                hibernate.
                HibernateTransactionManager">
  <property name="sessionFactory">
    <ref local="mySessionFactory"/>
  </property>
  </bean>

각각의 객체들은 스프링 설정 파일의 <bean> 태그 안에서 레퍼런싱 될 수가 있다. 위 예제에서 mySessionFactory빈은 HibernateSessionFactory 타입의 객체를 나타내고 myTransactionManager빈은 하이버네이트 트랜잭션 매니저를 나타낸다. transactionManger 빈이 그 프로퍼티로써 sessionFactory를 가지고 있음을 유의해서 보라transactionManger 의 클래스인 HibernateTransactionManager 클래스는 sessionFactory에 대한 setter메소드와 getter메소드를 가지고 있다. setter와 getter를 가짐으로 인해서 스프링 프레임웍 컨테이너가 시작될 때 설정 파일에 설정된 대로 setter를 호출해서 실제 구현 객체를 HibernateTransactionManager에 집어 넣어 transactionManger 객체를 생성하게 된다. 이런 흐름을 바로 연관성 삽입(dependency injection)이라고 부른다. sessionFactory 프로퍼티에  mySessionFactory 빈이 삽입되게 되는 것이다. 이 두 객체들은 스프링이 초기화될 때에 setter메소드를 사용하여 결합된다.  이런 결합 방식은 싱글톤 객체를 생성하고 그러한 객체들의 생성에 사용되는 Factory를 작성하는 수고를 덜어 준다. mySessionFactory 빈은 두개의 로퍼티(mappingResources,hibernateProperte)를 가지고 있다. 보통 스프링을 사용하지 않고 하이버네이트를 단독으로 사용할 댸 이런 프로퍼티에 대한 설정은 hibernate.cfg.xml 에 저장된다. 그렇지만 스프링은 스프링 설정 파일에다 하이버네이트 설정을 결합시킬 수 있게 함으로써 좀 더 설정을 쉽게 할 수 있게 한다. 좀 더 많은 정보를 원한다면  Spring API 문서를 참고하라.

비즈니스 서비스 객체와 DAO 객체를 결합시키기 위해 필요한 컨테이너 서비스 빈의 설정을 완료했다. 그러면 여기에다가 트랜잭션 매니져 객체만 결합시키면 된다.

여기에 완성된 스프링 설정 파일이 있다.:

<!-- ORDER SERVICE -->
<bean id="orderService"
  class="org.
         springframework.
         transaction.
         interceptor.
         TransactionProxyFactoryBean">
  <property name="transactionManager">
    <ref local="myTransactionManager"/>
  </property>
  <property name="target">
    <ref local="orderTarget"/>
  </property>
  <property name="transactionAttributes">
    <props>
      <prop key="find*">
     PROPAGATION_REQUIRED,readOnly,-OrderException
      </prop>
      <prop key="save*">
     PROPAGATION_REQUIRED,-OrderException
      </prop>
    </props>
  </property>
</bean>
<!-- ORDER TARGET PRIMARY BUSINESS OBJECT:
Hibernate implementation -->
<bean id="orderTarget"
         class="com.
                meagle.
                service.
                spring.
                OrderServiceSpringImpl">
  <property name="orderDAO">
    <ref local="orderDAO"/>
  </property>
</bean>
<!-- ORDER DAO OBJECT -->
<bean id="orderDAO"
         class="com.
                meagle.
                service.
                dao.
                hibernate.
                OrderHibernateDAO">
  <property name="sessionFactory">
    <ref local="mySessionFactory"/>
  </property>
</bean>

그림 4는 우리가 결합시켰던 것들을 개괄적으로 보여준다. 이 그림은 스프링에 의해 각각의 객체들이 어떻게 연관되어 있고 다른 객체에 어떻게 setting되는지를 보여준다. 예제 어플리케이션의 스프링 설정파일과 이 그림에서의 연관 관계를 같이 참고하면서 보면 이해가 빠를 것이다.

Figure 4
그림 4. 스프링이 설정 파일에 기초하여 빈들을 결합시키는 것을 보여주고 있다.

이 예제는 우리가 이전에 정의했던 트랜잭션 매니져에 대한 setter메소드를 가지고 있는  TransactionProxyFactoryBean을 사용하고 있다. TransactionProxyFactoryBean는 선언자를 사용한 트랜잭션 처리와 서비스객체를 다루는 기능을 갖고 있어 사용하기 편리하다. TransactionProxyFactoryBean을 사용하게 되면 트랜잭션이 적용될 메소드의 패턴을 정의하고 어떤 트랜잭션 룰이 그 메소드 패턴에 적용될 것인지를 결정하는 transactionAttributes프로퍼티를 통하여 어떻게 트랜잭션이 처리될 것인지를 정의할 수가 있다. 설정 격리 레벨와 트랜잭션 커밋,롤백에 대한 더 자세한 정보를 얻기를 원하면 TransactionAttributeEditor 를 참고하라.

TransactionProxyFactoryBean 클래스는 target프로퍼티에 대한 setter메소드를 가지고 있는데, target 프로퍼티는 orderTarget이라고 불리는 우리가 정의하는 비즈니스 서비스 객체가 레퍼런싱된다. orderTarget 빈은 어떤 비즈니스 서비스 클래스가 사용될 것인를 결정한다. 그리고 그것은 setOrderDAO() 같은 setter메소드를 통해 접근될 수 있는 프로퍼티를 가지고 있게 된다. 이 프로퍼티에는 우리의 퍼시스턴스 계층과 통신하는 orderDAO객체가 세팅된다.

스프링과 빈에 대해 알아야 할 한가지 사항이 더 있는데 그것은 빈은 두 가지 모드로 작동한다는 것이다. 이것은 싱글톤과 프로토타입으로써 정의된다. 기본 모드는 모든 곳에서 동일한 객체의 레퍼런스를 가지고 작업하게 되는 싱글톤 모드이다. 이것은 무상태 세션 빈(EJB에서의)이 제공하는 것과 같은 무상태 작업을 요구할 떄에 사용된다. 그리고 프로토타입 모드는 스프링 설정파일을 사용하여 결합되는 객체를 스프링에 요구할 때마다 새로운 인스턴스를 만들어 돌려주는 방식이다. 각각의 사용자가 작업 처리를 위해 각각의 객체 인스턴스를 필요로 하면 이 모드를 사용해야 한다.

서비스 로케이터(Service Locator) 제공

서비스 객체들이 DAO 객체들과 연결되어 이제 서비스 계층을 다른 계층과 결합할 수가 있게 되었다. 아래에서 보게 될 코드들은 일반적으로 스트럿츠나 스윙을 사용한 UI 계층에서 보게 될 코드들이다. 서비스 로케이터를 사용하여 스프링 컨텍스트에서 자원들을 빼내어 사용하는 것을 좀 더 쉽게 만들 수 있다. 물론 bean의 ID를 사용하여 스프링으로부터 직접 요청하여 자원을 빼내어 사용할 수도 있다.

여기에 스트럿츠 액션에 서비스 로케이터를 사용하는 예가 있다.(orderService라는 Action클래스의 Property로 서비스가 세팅된다.)

public abstract class BaseAction extends Action {
  private IOrderService orderService;
  public void setServlet(ActionServlet
                                 actionServlet) {
    super.setServlet(actionServlet);
    ServletContext servletContext =
               actionServlet.getServletContext();
    WebApplicationContext wac =
      WebApplicationContextUtils.
         getRequiredWebApplicationContext(
                                 servletContext);
      this.orderService = (IOrderService)
                     wac.getBean("orderService");
  }
  protected IOrderService getOrderService() {
    return orderService;
  }
}

UI 계층 설정

이번 예제에서 UI 계층 프레임웍으로 스트럿츠를 사용한다. 여기서 어플리케이션 계층화에 있어 스트럿츠와 관련된 내용에 대해 이야기해 볼 것이다. struts-config.xml 파일의 Action 설정을 살펴봄으로 시작해 보자.

<action path="/SaveNewOrder"
    type="com.meagle.action.SaveOrderAction"
    name="OrderForm"
    scope="request"
    validate="true"
    input="/NewOrder.jsp">
  <display-name>Save New Order</display-name>
  <exception key="error.order.save"
    path="/NewOrder.jsp"
    scope="request"
    type="com.meagle.exception.OrderException"/>
  <exception key="error.order.not.enough.money"
    path="/NewOrder.jsp"
    scope="request"
    type="com.
          meagle.
          exception.
          OrderMinimumAmountException"/>
  <forward name="success" path="/ViewOrder.jsp"/>
  <forward name="failure" path="/NewOrder.jsp"/>
</action>

SaveNewOrder 액션은 UI 계층에서 사용자가 전송한 order를 퍼시스턴스 상태로 저장하기 위하여 사용된다. 일반적인 스트럿츠 액션이라고 보여지나 이 액션에 대한 exception 설정은 주목해서 볼 필요가 있다. 이 exception들은 역시applicationContext-hibernate.xml 같은 비즈니스 서비스 객체 생성을 위한 transactionAttributes 등의 프로퍼티를 설정하는 스프링 설정 파일에도 설정된다. 비즈니스 계층에서 이러한 예외가 발생하여 UI계층으로 그 예외를 돌려주면 우리는 UI계층에서 그것들을 적절히 처리할 수 있다. 첫번째 예외인 OrderException 은 order객체를 퍼시스턴스 계층에 저장시 실패할 때에 이 액션 객체에 의해 사용될 것이다. 이것은 트랜잭션을 rollback시키며 예외를 비즈니스 계층에서 UI계층, 즉 스트럿츠로 보낼 것이다. OrderMinimumAmountException 은 최소 order 총량에 맞지 않을 때 비즈니스 로직상에서 발생하며 역시 트랜잭션 레벨에서 처리된다. 이 예외가 발생하게 되면 또한 트랜잭션 rollbackwill 이 발생하게 되며 이 예외를 받게 될 UI 계층에서 알맞은 처리가 이루어질 것이다.

마지막 결합 과정은 프리젠테이션 계층과 비즈니스 계층을 엮는 것이다. 이것은 이전에 설명했던 서비스 로케이터를 사용함으로써 이루어진다. 서비스 계층은 우리의 비즈니스 계층과 퍼시스턴스 계층에 대한 인터페이스로써 동작하게 된다. 여기에 SaveNewOrder 액션이 비즈니스 메소드를 호출하기 위해 서비스 로케이터를 사용하는 것을 보여주고 있다.

public ActionForward execute(
  ActionMapping mapping,
  ActionForm form,
  javax.servlet.http.HttpServletRequest request,
  javax.servlet.http.HttpServletResponse response)
  throws java.lang.Exception {
  OrderForm oForm = (OrderForm) form;
  // 퍼시스턴스 계층에 저장될 Order객체를 생성하기
  // 위해 폼을 사용한다.
  // 샘플 어플리케이션의 풀 소스를 참고하라.
  // 결합된 비즈니스 객체를 BaseAction에서 생성된
  // 서비스 로케이터로부터 얻어 사용하면 된다.
  // Order 객체를 저장하기 위한 서비스 계층의 작업과
  // 더 윗단에 있는 작업을 분리하고 있다.
  getOrderService().saveNewOrder(order);
  oForm.setOrder(order);
  ActionMessages messages = new ActionMessages();
  messages.add(
      ActionMessages.GLOBAL_MESSAGE,
     new ActionMessage(
      "message.order.saved.successfully"));
  saveMessages(request, messages);
  return mapping.findForward("success");
}

결론

이 글은 기술과 구조의 측면에서 상당히 많은 넓은 부분을 다루고 있다. 기본 개념은 이렇다. 더 좋은 어플리케이션을 만들기 위해서는 유저 인터페이스 계층과 퍼시스턴스 계층과 또 다른 계층들을 분리해야만 한다는 것이다. 그런 것을 잘 하는 것은 코드량을 줄일 수가 있고 새 컴포넌트의 추가를 용이하게 만들며 차후에 있게 될 유지보수를 쉽게 만든다. 여기서 다루어진 기술들은 특별한 분야에 대한 문제를 잘 해결해 줄 수도 있다. 하지만,  이런 구조를 사용함으로써 각각의 어플리케이션 계층에 다른 기술을 사용할 수도 있다. 예를 들면 당신은 퍼시스턴스 계층의 구현을 위해 하이버네이트 프레임웍을 사용하고 싶지 않을지도 모른다. DAO 객체 구현에 있어 인터페이스를 사용하여 코딩하고 있기 때문에 거기에 다른 기술이나 프레임웍( iBATIS 등) 을 사용하는 법은 어떻게 보면 명백하리만큼 쉬운 것인지도 모른다. 아니면 UI 계층을 스트럿츠 말고 다른 프레임웍으로 교체하고 싶을지도 모른다. 단순히 UI 계층의 구현을 변경하는 것은 비즈니스 로직이나 퍼시스턴스 계층에 영향을 미치지 않는 것이 우리가 지금까지 설명했던 구조의 특징이다.  역시 퍼시스턴스 계층의 변경은 UI 계층이나 서비스 계층에 영향을 미치지 않을 것이다.  웹 어플리케이션을 제작한다는 것은 쉬운 일이 아니다. 하지만 어플리케이션의 각 계층들을 분리하여 제작하고 적절한 프레임웍을 사용하여 결합함으로써 어플리케이션을 제작하는 것이 그 쉽지 않은 작업들을 좀 더 편하게 만들어줄 수 있다.

마크 이글 은 Atlanta, GA.소재의 MATRIX Resources 의 선임 소프트뤠어 연구원으로 일하고 있다.


Return to ONJava.com.

Copyright © 2004 O'Reilly Media, Inc.

반응형
반응형

예전 블로그 복사 http://blog.daum.net/7dbwnckd/2762431 


VTL 문서에는 없어서 정리해봄!

 

1. velocity macro 의 사용

 

#macro(test)

  <tr>

      <td>test</td>

  </tr>

#end

 

 #test() 라고 사용한다.

 

또한 파라메타를 받을 수 있음

 

#macro(test $a)

  $a

#end

이렇게도 된데요 ㅋㅋ 해보지는 않았어요.

반응형

+ Recent posts