안웹개발자 수준으로 개인 블로그 만들기


elinjkim.github.io






'Development > Etc.' 카테고리의 다른 글

type(형)  (0) 2016.02.06
언어별로 문자열 처리  (0) 2016.02.06
전역스코프 동적스코프 정적스코프  (0) 2016.02.06
상속이 is-a 관계여야 하는이유와 delegation  (0) 2016.02.06
언어별 클래스의 의미  (0) 2016.02.06


형은 데이터에 붙은 추가데이터다.

컴퓨터는 데이터를 on/off, 1과 0의 집합으로 표현한다.

같은 비트열 형식이지만 컴퓨터가 어떻게 처리할 지를 CPU에 알리는 것이 형의 시작이다.



데이터를 지금의 비트열로 표현하기 까지는 많은 과정이 있었다.

적은 수의 on과 off를 이용해서 많은 데이터를 표현할 수 있어야 한다.


그래서 자릿수나 8진수, 16진수가 나온것이다.

 

1983년에 닌텐도가 출시한 패밀리 컴퓨터는 8bit를 사용했고, 현재는 보통 64bit를 이용해 데이터를 표현한다.


파이썬 3.0 에서는 8비트, 1


즉, 형이 생기게 된 근본적인 이유는 컴퓨터의 연산처리와 관계가 있는데 변수형 선언을 함으로써 정수는 CPU는 어떤 계산을 할 지 아는 것이다.

이렇게 알리는게 중요한 이유는 예를들어 부동소수점과 고정소수점의 연산 방법에는 차이가 있기 때문이다. 




그렇다면 형은 어떻게 발전하였을까?


1. 이런 기본형 외에도 개발의 편의를 위해서 사용자가 임의로 형을 정의할 수 있게 되었다.

C언어의 구조체가 대표적인 예이다. 

실제로 리눅스는 OOP의 개념을 굉장히 추구하고 반영하고 있는데, C로 작성되었기 때문에 OOP를 클래스가 아닌 구조체 단위로 구현한다.


C++ 설계자인 바얀교수는 사용자가 정의하는 형이야 말로 프로그램 구축에 기본요소라 생각하여 개념을 도입했고, 클래스라고 이름을 붙였다.


2. 형은 통해서 접근레벨을 사용하여 public, private같은 접근권한을 설정 할 수 있게 되었다.

구조체나 클래스를 구성하는 형을 최소한만 공개하여 코드를 보호한다는 의미이다. 형이 맞는지 틀린지는 컴파일단계에서 컴파일러가 해준다. 그래서 이런 사양을 형으로 표현하게되면 우리는 개발을 할 때 컴파일러에게 유용한 도움을 받을 수 있게 되는 것이다.


3. 이런 개념은 인터페이스로까지 발전되었다. 인터페이스 처럼 추상적인 개념을 개발할 때 컴파일러가 오류를 검출해 주기때문에, 우리는 잘못된 코드를 작성할 걱정과 수고를 덜 수 있게되었다.





형은 다시 재정의 할 수 있다. 다시 말하면 기존의 형을 구성 요소의 일부분을 바꾸어 다시 재사용 할 수 있다는 말이다.

C++의 template, Java의 generics,  Haskell의 형 생성자 등이 해당된다.









출처. 코딩을 지탱하는 기술

컴퓨터 이전의 부호화


모스부호 morse code,

1836년에 발명되어 1865년 International TelegraphyCongress에 의해 국제표준화 구격이 된 부호화 방법이다.

무선기에 연결된 스위치를 통해 전파를  On/Off로 입력하여 통신에 이용한다.


보코드

모스부호는 사람이 직접 수고를 하였다. 통신 분야가 발전하면서 보다 빠른 송신방법이 요구되었다.


텔레타이프 단말기가 등장하였는데, 타자기가 전화선에 연결되어있는 모양으로 키보드를 눌러서 문자를 입력하고 수신자는 수신한 문자를 프린터로 출력할 수 있었다.


이후 보다 많은 양의 정보를 교환하려는 필요가 생기고 펀치 테이프와 가독기를 연결하여 사용하게 되었다.


사람이 송신하고자하는 내용을 미리 펀치테이프에 기술하여 기계가 읽어들여 송신할 수 있는 구조이다.


이 텔레타이프 단말기가 연결된 국제적 통신기가 텔렉스다.

1931년에 최초로 서비스가 시작되었고 여기서 사용한 방식이 baudot code이다.


한 문자당 5bit로 on/off의 조합을 가진다. 즉 SOS는 총 15개의 bit로 표현하였다. 또 공백, 개행 등 제어 코드를 문제 세트에 추가하였다. 



EDSAC 문자코드

텔렉스로부터 약 20년 후 199년에 만들어진 EDSAC.


한 문자에 5bit를 사용하고 천공테이프(종이테이프에 구멍을 뚫어서)를 이용했다.


ASCII와 EBCDIC

EDSAC 이후에 10년간 다양한 컴퓨터가 만들어졌고, 문자 부호화 방식도 제각각이었다.

제각각인 문자 부호화 방법을 표준화하기위해 American Standard Code for Information interchange의 약자로 ASCII가 1963년에 제정의 되었다.


한 문자당 7비트를 사용하여 127종류의 문자를 표현했고 여기부터 소문자도 포함


하지만 1963년 이당시에 컴퓨터 시장을 장악하고 있던 IBM이 ASCII와 다른 EBCDID방식을 공개하였다.  결국 통일이 안되었고 심지어 EBCDID자체에도 여러 버그가 존재했다.

다른 부화화방식(문제체계와)과 호환에 문제가 있었다.


계속 불편..

결국 1984년 전 세계의 문자 부호화 방법을 통일하자는 움직임이 시작됐고 1984년 ISO가 universal Character Set(UCS) 표준화를 시작.

Xerox도 이와 별도로 1987년에 작업을 시작해서 1989년 최초 시안의 Unicode Draft1을 공개. 

결과적으로는 Unicode에 ISO의  USC가 일체화 되는 형태로 1993년에 국제화 표준이 됨 


이래서 전세계 문자를 포함한 문자집합 Unicode가 탄생





현재 프로그램 언어가 표현하는 문자열은 두가지가 있다.

C언어의 문자열은 자신의 길이를 알지 못하고, Pascal, Java, Ruby, Python은 문자열의 길이를 알고있다.




1. C 

하나의 문자를 8비트로 정의한다.

C언어의 문자열은 문자열이 시작되는 메모리상의 위치를 가지고있고 길이 정보를 가지고 있지 않아서 해당 위치에서 어디까지가 문자열인지 알수가 없다.


문자열의 끝을 표시하기 위해서 C언어는 문자열의 끝에 NUL 문자를 삽입한다. 

NUL은 0에 대응하는 문자이며 코드상에서는 \0으로 표현한다.


* ASCII에서 null character를 NUL이라고 쓰기로 정의한다.

C언어는 pointer를 다루는데 NULL pointer라는 개념이 있어서 문자열에 대한 NULL은 ASCII에서 표현하는 NUL이라고 기재하도록 한다.


8비트로 표현할 수 있기때문에 0~255로 표현할 수 있는 ASCII, 혹은 EBCDID의 문자



2. pascal 도 한 문자당 8비트로 표현한다.

하지만 pascal의 문자열은 문자열 앞부분에 길이정보를 가지고 있다. 대부분의 언어들은 문자열을 표현할 때 이와같이 표현되고있다.


3. java

자바에서는 한 문자는 16비트로 표시된다.

16비트로 표현되므로 0~65,535로 표혛날 수 있는 Unicode의 한 문자이다.



python은 자바와 같이 16비트의 unicode문자열과 pascal과 같은 8비트 문자열을 모두 지원한다.

python2 에서는 소스코드에 '아'라고 하면, UTF-8인 경우 3개의 바이트가 들어간 ['0xe3'. '0x81', '0x82']로 되고

u"아"라고하면 유니코드로 ['0x3042']가 된다.


파이썬2에서는 바이트열이 ASCII범위에 포함되면 ASCII로 간주되고 자동으로 UNIcode로 변환하는 설계로 되어있었다.

오로지 Unicode문자열에 바이트열을 결합하기 위해선 ASCII로만 이루어져있어야 가능했다.


하지만 이는 ASCII를 사용하지 않는 나라에서는 문제가 되었다. 

그래서 파이썬 3에서는 이전버전과의 호환성을 아예 버리더라도 유니코드가 기본이 되도록 하였다. 즉 '아'라고 하면 유니코드 문자열이 되고,

b'아'라고하면 8비트 문자열이 되도록 변경하여 유니코드를 손쉽게 사용할 수 있도록 하였다.  

그리고 문자열 형식의 형변환 시 명시적으로 하도록 했다. 


즉 유니코드 문자열에 바이트 문자열을 붙일 시에는 명시적인 형변환으 통해서 바이트 문자열을 유니코드로 형변환 한 후 문자열을 결합하여야 한다.







출처. 코딩을 지탱하는 기술

전역스코프 동적스코프 정적스코프


일반적으로 스코프를 사용하여 이름의 유효범위를 지정 해야한다. 스코프는 어떻게 동작하는지 알아보자.



동적스코프

전역에 x라는 변수가 있다고 하자. 그리고 지역함수에도 x라는 변수가 있다고 하자.

지역함수에 들어오면 전역에 위치한 x가 어떤 값을 가지고 있더라고 지역함수 내의 x는 지역함수 내에서 만큼은 값을 보장받을 수 있다. 즉 지역함수 내에서는 갓이 유효하다.

이는 전역의 변수의 값을 다른 곳에 저장한 후 지역함수를 빠져나갈때 값을 되돌리기 때문이다. 이를 수행해 주는것이 동적스코프이다. 참고로 perl 4(1991년) 부터는 변수를 local이라는 키워드로 선언하면 이를 알아서 해준다. 



Perl


$x = "global";


sub yobu {

local $x = "yobu";

&yobareru();

}


sub yobureru {

print "$x\n";    # yobu 라고 출력됨

}


&yobu();


이 예제에서는 yobu() 함수의 지역변수 x가 sub함수 yobareru()까지 영향을 미친다.

동적 스코프는 변경값이 호출되는 곳에 파급되기 때문에 어떤 값이 될지 코드를 보지 않고서는 알 수 없다. 코드의 양이 많아지면 정말 귀찮은 일이 될것이다.


변수들의 데이터를 다른 곳에 저장하는 대신 대웅표라는 것을 만들어 관리한다. 

동적 스코프와 전역 스코프는 이 대응표를 프로그램 전체에 결쳐서 몇 개의 함수가 공유하고 있다. 


함수에 들어가면 새로운 대응표가 만들어진다

해당 함수 안에서의 내용은 대응표에 기록되지고 사용된다.

해당 함수를 벗어날 대 이 대응표를 제거한다.


그리고 변수를 참조할 때에는 가까운 곳에서 부터 순서대로 읽는다.
이것이 위의 예제에서 결과가 yobu인 이유이며, 만약 지역에 변수가 없다면 전역변수의 값이 출력될 것이라고 짐작할 수 있겠다.

 여러 함수에서 대응표를 공유하기때문에 문제가 발생한다면 함수별로 대응표를 나눠볼 수 있을 것이다. 이것이 정적스코프가 동작하는 개념이다.


함수에 들어가면 해당 함수 전용의 새로운 대응표를 준비한다.

함수내에서의 내용은 해당 대응표에 기록되고 사용된다

함수를 빠져나갈때 해당 대응표를 제거한다.


정적스코프라고 가정하에 다시 예제를 보자.


Perl


$x = "global";


sub yobu {

my $x = "yobu";

&yobareru();

}


sub yobureru {

print "$x\n";    # global 라고 출력됨

}


&yobu();



yobareru에서 x를 참고할 때 해당 함수의 대응표에는 x가 없다. 그러므로 yobu함수의 대응표가 아닌 바로 전역을 읽는다. 

우리는 이 방식이 일반적인 것이라고 생각한다. 그렇다. 현재 많은 언어가 정적 스코프를 도입하고 있기 때문이다. 


JavaScript에서도 var를 붙이지 않으면 전역스코프이고 var를 붙이면 정적스코프이다. 

몇몇 언어들은 스코프방식이 변하기도 했다.


Python은 처음부터 정적 스코프였다. 

Python2.0 에는 스코프가 3가지가 있다.


지역, 전역, 빌트인

빌트인은 프로그램의 어디에서든 참조할 수 있는 스코프이며 여기에는 문자열화 함수stir이나 Runtime(실행 시)  Error등이 있다.

이는 언어에 기본 탑재되어 있는 함수나 예외이므로 빌트인이라고 한다. 



python2.0에서 전역 스코프는 파일 단위로 존재한다. 따라서 파일 스코프라도고 한다. 


 


python은 대입과 함께 변수를 만드는 언어이다. 함수안에서 대입을 하면 아무것도 선언하지 않더라도 지역변수가 된다.

이는 두가지 문제를 만들 수 있다.



이제 파이썬에서 발생할 수 있는 스코프 문제를 살펴보자


첫번째, 





실제로 2.0 버전에서는 함수 bar()의 지역 스코프에서 이름 x를 발견하지 못하면 전역스코프를 보러 가는 설계로 되어있다(그림7.9의 1번). 

결국 수정할 필요가 있는 문제점이라고 인식되어 2001년에 공개된 Python2.1에서는 그림7.9의 1번처럼 동작하도록 수정되었다.




두번째, 


대입과 함께 변수를 만들기 때문에, 함수에 지역변수가 없으면 바로 지역스코프 변수로 생성한다.

처음에는 JavaScript처럼 var변수를 이용해서 해결하고자 했지만, 과거 코드와 호환성이 없어서 채택되지 않았고


2006년 3.0버전에서 nonlocal이라는 키워드로 선언하여 사용하도록 채택되었다.




이런 스코프 개념은 언어마나 한가지로 정의되지는 않는다.


자바의 경우 정적스코프의 언어이지만 java의 클래스는 소스코드 어디서든 참조할 수 있다. 

즉 클래스는 전역 스코프를 사용하는 것이다. 클래스는 이름이 계층적으로 이루어져있고, 임포트하지 않으면 사용할 수 없어서 전역변수가 가지고 있던 충돌 문제를 피한다. 

그리고 잘 알고있는 static 변수도 전역스코프의 변수이므로 소스코드 어디든지 바꿀 수 있다. 

하지만 static변수를 사용할 때 주의를 해야하는 이유는 남용하게되면 이해하기 어려운 코드가 되기 때문이다.






출처. 코딩을 지탱하는 기술

'Development > Etc.' 카테고리의 다른 글

type(형)  (0) 2016.02.06
언어별로 문자열 처리  (0) 2016.02.06
상속이 is-a 관계여야 하는이유와 delegation  (0) 2016.02.06
언어별 클래스의 의미  (0) 2016.02.06
이벤트기반과 메세지기반 아키텍처의 차이  (0) 2016.02.06


클래스를 이야기 할 때, 부모클래스와 자식클래스라는 이야기를 많이 한다.

이를 빌어 쉽게 이야기하면 자식클래스는 부모클래스를 상속하여 구현한다. 라고 말한다.


좀더 프로그래머의 관점에서 보도록하자.


1. 상속은 부모 클래스로 기본적인 기능을 구현한다. 그리고 자식 클래스로 상속받고 좀 더 특화된 기능을 구현한다. 자식 클래스는 부모 클래스를 특수화한다고 생각 할 수 있다.

2. 부모클래스를 기본적인 기능으로 구현할 때 공통된 것을 추출하여 구현할 수 있겠다. 즉 자식클래스는 부모클래스의 일종이 아니다. 같은 것이 아니란 이야기이다.

3. 공통된 부분을 부모클래스가 가져가고 추후에 각 자식클래스는 추가되거나 수정되는 기능을 구현하면 효율이 좋다.


이렇게 상속을 이용하면 높은 자유를 제공한다. 하지만 상속을 많이 사용하면 코드가 복잡해지고 이를 정상적으로 동작시키도록 제어도 추가해야 할 수 있다. 


상속과 관련하여 리스코프의 치환 원칙이라는 것을 주의해야 할 사항으로 자주 언급된다.

리스코프의 치환 원칙은 CLU라는 언어의 설계자인 Liskob가 1987년에 제창한 하였다. 


T형의 객체 x에 관해 어떤 속성 q(x)가 항상 참이라고 한다. 

S가 T의 파생형이면, S형의 객체 y의 속성 q(y)가 항상 참이어야 한다.


이는 어떤 클래스 T의 객체인 x의 속성이 참이라면, 그럴 상속받은 자식 클래스 S의 해당 객체도 항상 참이어야 한다 라는 말이다.


즉 현실세계에서는 모르겠지만, 객체지향에서의 상속은 부모에게 구현되어 있는 속성들에 대해서는 자식들의 것들도 모두 만족해야 한다는 이야기이다. 

결국 이런 상속관계와 형의 부자관계간 정합성을 유지하는게 중요하다. 


이를 위해 상속은 is-a관계를 성립해야 한다. 라고 표현한다. 그리고 클래스 상속과 형 구조의 정합성을 유지하기에는 굉장히 어렵다. 



자식으로 진화할 수록 할 수있는 기능이 다양해질 수 있다.

예를 살펴보자. 


Windows 환경에서 창(window)이라는 부모 클래스 A가 있다.

이를 상속받는 자식 클래스가 두개있다. 하나는 메뉴바가 있는 클래스 B이고 하나는 스크롤바가있는 클래스 C이다.

이 상태에서 메뉴바도 있고 스크롤바도 있는 클래스 D를 만들고 싶다.

만약 D를 구현하기 위해서 A를 상속받은 후 B, C 클래스의 내용을 구현한다고 해보자. 이는 불필요할 수 있다. 왜냐면 D가 B,C 를 상속받을 수 있기 때문이다. 이를 다중상속이라고 한다. 다중상속을 하면 별도의 코드를 다시 만들 필요가 없게된다. 


Python 표준 라이브러리에서 사용되고있는 다중상속의 예를 보자.


class ForkingUDPServer(ForkingMixIn, UDPServer): Pass

class ForkingTCPServer(ForkingMixIn, TCPServer): Pass

class ThreadUDPServer(ThreadingMixIn, UDPServer): Pass

class ThreadTCPServer(ThreadingMixIn, TCPServer): Pass


이 라이브러리들은 통신에 TCP, UDP를 이용할지와, 병렬처리방법으로 fork를 이용할지 thread를 이용할지에 관한 내용이다.

이는 각 부분의 속성을 하나씩 속성받아 구현된 함수이다. 


이렇게하면 기존의 코드를 유용하게 그대로 사용할 수 있다.



하지만 다중 상속에는 주의할 점이 있다. A 클래스와 B 클래스모두 x라는 이름을 갖는 변수가 있다고 생각해보자. 이 둘을 상속받는 클래스 C에서 x를 참고할때 과연 어느 부모에게서 참조를 해야하는 것일까? 


Java에서는 이런 문제를 고려하여 다중상속을 금지하기로 했다. 하지만 다중상속이라는 편리함도 버리게 된다.  즉 코딩 시 재사용을 목적으로 한 상속을 피하려는 의지가 강하다. 예를들어 Abstract Window Toolkit(AWT)라는 그래픽 툴킷에서는 다시 상속한 각종 메소드를 오버라이드하여 사용한다라는 규칙을 만들기도 하였지만 이클립스 등에서 사용되는 Standard Wiget Toolkit(SWT)은 계승하면 안된다라는 규칙이 있다.


이를 대신하여 발달된 것이 delegation 이라는 개념이다.

사용하고 싶은 코드를 가지고있는 클래스 객체를 만들고, 필요에 따라서 해다 클래스에 처리를 맡기는 것이다. 이렇게하면 상속을 사용함으로써 형이나 이름 공간까지 함께 계승하는 것이 문제의 원인이기  때문에 단순히 객체만 보유하면 위의 문제를 막을 수 있다.


자바의 코드를 예를 들어보자.


pubilc class TestDelegate {

public static void main(String[] args) {

new UseInheritance().useHello();    // -> hello!

new UseDelegate().useHello();        // -> hello!

}

}


class Hello{

public void hello(){

System.out.println("hello!");

}

}


class UseIngeritance extends Hello{

public void useHello(){

hello();

}

}


class UseDelegate{

public void useHello(){

Hello h = new Hello();

public void useHello(){

h.hello()

}

}

}


위의 코드는 상속을 사용한 코드 재사용과, delegation을 사용한 코드 재사용을 나타내고 있다.

실제로 상속보다는 delegation을 이용한 방법이 훨씬 낫다. delegation의 참조도 소스에 하드코딩하는 것이 아닌 설정 파일을 사용해서 실행시에 주입하는 것이 편하다. 이런 발상으로 의존성 주입(dependency injection)이 탄생했다.



하지만 java에서도 다중상속을 금지하고 있긴하지만 interface라는 개념으로 다중상속을 구현한다. 

인터페이스는 코드를 가지지 않는 클래스이며 반드시 자식 클래스에서 이를 구현해야한다. 이를 추상클래스의 의미이다.


단도직입적으로 말하자면 상속을 코드 재사용을 위해서 하고싶다. 다른 방법은 없을까? 라고 생각할 수 있겠다.

이는 interface를 사용해 has-a관계를 가지며 구현할 수 있겠다.


java 에서는 상속(abstract)를 extends 키워드로, interface는 implement 키워드로 구현한다.


.



참고. 코딩을 지탱하는 기술

'Development > Etc.' 카테고리의 다른 글

type(형)  (0) 2016.02.06
언어별로 문자열 처리  (0) 2016.02.06
전역스코프 동적스코프 정적스코프  (0) 2016.02.06
언어별 클래스의 의미  (0) 2016.02.06
이벤트기반과 메세지기반 아키텍처의 차이  (0) 2016.02.06



 본디..


C++의 설계자인 바얀(Bjarne Stroustrup)교수님은 Class를 사용자 정의형을 만들기위한 구조라고 하고, 객체지향 프로그래밍이란 사용자 정의형과 상속을 사용한 프로그래밍이다. 라고 했다. C++은 클래스의 개념이 처음 나오고 난 후로부터 10년 뒤 Simula라는 시뮬레이션용 언어를 참고로 사용자가 형을 정의할 수 있도록 만들었다. 


클래스는 type이다. 이거이 C++을 이루는 아주 중요한 원리이다. C++에서 class가 사용자 정의 타입을 의미한다면 왜 그것을 type이라고 부르지ㅏ 않는가? 내가 class를 선택한 것은 계속 나오는 새로운 용어를 발명하는 것이 귀찮았기 때문이고, Simula의 class라면 아무도 당황하지 않을 것이라 판단했기 때문이다.

<C++로 배우는 프로그래밍의 원리와 설게>


int나 float처럼 동일하게 다룰 수 있는 새로운 형을 사용자가 정의하고 사용할 수 있게 하자 라는 것이 C++이 클래스를 도입한 목적이다. 

이렇게 되면서 Type을 자유롭게 만들 수 있게 되었고, MS에서 만든 Visual C++의 경우 너무 많고 다양한 형으로 이제는 사용하기 오히려 어렵기까지 되었다.


C++에서는 클래스를 형(type)으로 보고 객체가 어떤 메소드를 가지고 있고, 가지고 있지 않은가를 구분하는데 중요하게 생각했고 존재하지 않는 메소드를 호출하면 에러가 발생한다. 


하지만 객체지향 용어의 발명자인 Alan Kay는 객체지향이란 상태를 가진 객체가 메시지를 주고 받아서 커뮤니케이션하는 프로그램이라고 말하며, 형이나 상속에 대해서는 부정적인 입장을 취하고 있다. 그가 설계한 Smalltalk이란 것에서는 메소드 호출이란 건 단지 이런 이름의 메소드를 호출해달라는 메시지를 객체에 전달하는 것일 뿐 그 메시지를 받은 객체가 어떤 동작을 할지는 수신 객체가 자유롭게 결정할 수 있다. Alan kay는 이런 자유가 객체지향의 중요한 요소라고 생각한다.



실제로 언어의 성격이나 철학마다 설계자의 생각에 따라서 의미가 조금은 다르다. 실제로 클래스의 의미도 일반적으로 생각하면 위험할 수 있다.


그럼 형이라는 관점에서의 클래스는 어떻게 정의될까?

정적 형결정 언어인 C++에서는 클래스를 사용자가 정의할 수 있는 형이라고 한다. 

동적 혈결정 언어인 Ruby나 Python, Perl, JavaScript의 클래스는 아마 C++의 class와는 다른 의미를 가질 것이다.



보통 C++은 클래스가 없어도 프로그램을 만들 수 있다. Python이나 Ruby도 이와 마찬가지이다. 

하지만 Java는 다르다. Java는 클래스라는 부품을 정의하고, 그것을 조립해나가는 것이 프로그래밍이라고 정의한다. 따라서 Java에서는 클래스는 필수적 요소이다.



클래스는 사실 어떠한 비슷한 것들을 하나로 묶어서 만들자라는 것에 목적을 가진다. 그렇다면 클래스 이전에는 이를 위해 어떠한 개념들이 있었을까?


첫번째는 module이다. 비슷한 기능을 하는 함수를 하나로 모아두는 기능이다. 

1978년경 Modula-2가 개발되었는데 관련성이 높은 함수나 변수의 묶음을 명시하기 위해 Module이라는 개념을 도입했다고 한다.  Ruby나 Python에서는 module이라고 하며, Perl이나 Java에서는 Package라고 한다.


이런 비슷한 것들은 묶으면 현실 세계의 어떤 것을 구현해 낼 수 이씨 않을까? 라는 생각이 등장하게 되었다.


Perl의 package는 함수나 변수를 하나로 묶어서 이름을 붙일 수 있는 기능이다. 하지만 좀 더 완벽한 객체지향을 도입하기 위해서 hash를 사용한다.

자 이유를 생각해보자. pakage를 만들어 하나의 사물을 구현했다. 하지만 그 사물은 여러개일 수 있다. 그럼 이 pakage를 복사해서 pakageA, pakageB 이런식으로 이름을 붙여야 한다. 이게 과연 옳은 것일가? 아니다. 이를 해결하기 위해 별도의 데이터 저장소를 만들어 하나의 이름으로 관리하되 각 객체들이 사용하는 공간을 여러개 두는 개념이 생겼다. 이를 위해 hash를 사용한다. 그리고 추가해야 할 상황이 오면 이와같은 작업을 수행해줄 생성자 함수(constructor)도 필요하다. 이런 초기화 처리도 패키지에 넣는다.

그리고 편리한 사용을 위해 package명과 hash를 연결하는 기능인 bless라는 개념을 발명했고 이를 통해 bless된 hash를 만들어서 보다 편리하게 접근할 수 있도록 하였다.


두번째는 함수도 변수도 동일하게 hash에 넣는 방법이다. JavaScript는 First Class라는 것을 사용하여 구현한다.

일반적으로 대부분의 언어에서 변수에 문자열을 대입하여 사용할 수 있지만, 다 그러한 것은 아니다. FORTRAN66 에서는 문자열을 변수에 대입할 수 없고 C언어 에서는 배열을 인수로 함수 호출을 할 수 없다. 이러한 관점에서 보았을 때 Fisrt Class란 제한이 없는 변수에 대입하고, 함수의 인수로 전들하고, 함수의 반환값으로 전달할 수 있는 것을 말한다. JavaScript에서는 함수도 퍼스트 클래스의 값이라 함수를 변수에 대입하거나 반환값으로 전달하는게 가능하다. 그래서 함수도 hash에 넣을 수 있다.


이렇게 되면 어떤 기능을 하는 객체를 해쉬에 넣고 여러개를 만들 수 있게 되는 것이다. 또한 공유도는 사물은 하나로 묶어서 개별 카운터가 그것을 참조하는 형태로 구현되어 메모리나 시간 절약에 도움을 준다. 


세번째는 Closure이다. 함수 실행시에 이름공간의 변수를 하나로 묶기 위해서 사용하는데, 주로 함수형 언어에서 사용한다.

클로저는 JavaScript에서도 제공한다. 함수를 함수 안에 정의하고, 내포할 수 있는 정적 스코프가 있어서 함수를 반환값으로 사용하거나 변수에 대입하여 사용할 수 있다는 개념이다. 






출처. 코딩을 지탱하는 기술





이벤트기반과 메세지기반 아키텍처의 차이를 간단하게 컴퓨터의 역사를 통해서 철학적으로 생각해보자.





과거 초기의 컴퓨터에서는 하나의 프로그램을 실행하면 그 프로그램의 수행이 끝날때까지 해당 처리만 할 수 있었다.


데이터 입출력을 생각해보자.


파일을 수정하기 위해 텍스트 파일을 열었다. 이때 하드디스크로부터 메모리로 파일의 내용을 load할 것이다.

지금에야 파일의 용량이 상당히 크더라도 금방 로딩이 되지만, 과거 성능이 좋지 않았을 때에는 해당 내용을 읽어오는 작업 만으로도 상당한 시간이 걸렸을 것이다.

처리를 하나씩만 할 수 있다면 데이터를 읽어오는 시간동안은 데이터를 읽는 작업만 수행할 수 있고 해당 작업이 끝날때까지 기다려야 한다는 것이다. 

게다가 이런 I/O작업은 I/O 디바이스에서 수행되므로 CPU는 가만히 놀고있게 된다. 굉장한 자원의 낭비이다. 

이는 지금에선 상상도 할 수 없는 끔직한 일이다. 


데이터를 읽어오는 동안 다른일을 할 수 있다면 굉장히 효율적일 것이다. 이를 실현하기 위해 프로세스, 스레드라는 개념이 만들어지며 병행처리가 가능하게 되었다.

프로세스, 스레드를 이용해 자원을 나누어 여러개의 일을 동시에 처리하는 것처럼 할 수 있다. 어떤 방법으로 자원을 공유할 것인지는 어떤 스케줄링 방식을 사용할 것인지에 따라 달라진다. 만약 이런 스케줄이 없다면 자원에 대해서 접근하는 여러 작업들간에 충돌이 일어날 것이다. 이를 막기위해 스케줄을 구현하는 스케줄러는 Lock이나 fiber등의 개념을 사용해서 충돌을 방지할 수 있다.


기본적으로 병행처리를 하는 방법은 두가지로 나눈다.

preemptive multi-task(선점형 멀티태스크)방식이과 non-preemptive multi-task(비선점형 멀티태스크)방식이다.


non-preemptive multi-task는 한 처리가 수행될 때 CPU를 독점하고 있므면서 CPU가 프로세스들의 수행제어에 관여하지 않는 방식이다. 즉 수행중인 프로세스가 자신의 처리가 다 끝나거나 혹은 자발적으로 수행을 그만할 때 비로소 제어가 다른 쪽으로 넘어갈 수 있다. 한번 프로세스가 실행되면 다른 처리는 계속 기다려야 하므로 최적의 어떠한 간격을 두고 교대를 해야한다 라는 전제조건을 릴요로 한다. Windows 3.1이나 NT와 Max OS 9가 이 방식을 사용했다. 문제가 발생하면 다른 프로세스에게 제어가 자연스럽게 넘어가지 못하므로 통째로 백업해야하는 단점도 있다. 


preemptive multi-task 방식은 CPU가 프로세스들의 수행제어에 선점적으로 관여한다. 일정 시간이 지나면 현재 진행중이던 처리를 강제로 중단한 후 다음의 프로그램이 수행되도록 한다. 이는 UNIX나  LINUX가 선택한 방식이기도 하다.


preemptive 방식에서 프로세스들은 자신의 수행이 언제 중단될지 알 수 없기 때문에 이들을 제어하는 스케줄러의 역할은 매우 중요하다. 만약 잘못한다면 데이터나 자원의 상태가 꼬이거나 충돌이 발생할 수 있기 때문이다. 이런 상태를 race condition 혹은 non thread safe라고 한다.

그리고 처리 도중 끼어들 수 있는 개념이 interrupt이며 이를 이벤트기반의 아키텍처라고 볼 수 있겠다. 즉 이벤트 기반이라는 것은 어떤 일이 발생하였을 때 해당 이벤트를 알려주고 해당 이벤트에 맞는 처리를 수행한다는 것이다. 소프트웨어 개발의 관점에서 봤을때에도 마찬가지로 이벤트를 발생시키면 이벤트를 받는 쪽에서는 해당 이벤트를 수행할 수 있다. 보통 실시간 작업처리를 위해 사용된다.


race condition을 발생하는 조건은 다음과 같다.

1. 2가지 처리가 변수를 공유하고 있음.

2. 적어도 하나의 처리가 그 변수를 변경할 수 있음.

3. 한쪽 처리가 한 단락 마무리 되기 전에, 다른 쪽의 처리가 끼어들 가능성이 있음.


race condition을 방지하거나 해결하려면 위의 사항 중 하나만이라도 처리하면 된다. 


첫번째 항목을 살펴보자. 처음부터 공유하는 것이 없도록 만들면 된다.

처음의 시스템은 메모리를 공유하는 방식이었지만 1969년 발표된 Multics라는  OS에는 다양한 기능들이 많이 들어가면서 시스템이 복잡해 졌으며 이를 해결할 방법이 필요했다. 이를 해결하기 위해 1970년에 UNICS라는 OS가 만들어졌고 이것이 현재의 UNIX이다. UNIX는 프로세스별로 메모리영역을 따로 지정하여 사용하는 구조를 가진다.


하지만 이런 방식은 성공하지 못했다. 프로세스끼리 정보를 공유해야 하는 경우도 있었기 때문에 메모리공유가 필요했던 것이다. 스레드는 여기서 나온 개념이다.



병행처리의 다른 모델로 actor 모델이라는 것이 있다.

위에서 설명한 병행처리에서는 프로세스들이 정보를 교환하는 방법으로 메모리를 공유하였다. 이를 위해서는 lock이라는 것을 이용하여 다른 프로세스의 접근을 막아야 했고 locking이 수행되다면 어떤 처리가 끝날때까지 기다려야하는 프로세스가 생기게 된다. 즉 자원이 비효율적으로 사용 될 수 있다는 것이다. 

자신(A)의 처리에 필요한 다른 처리의 수행을 위해 프로세스(B)가 필요하다고 가정해보자. 만약 A가 B에게 바로 알리게 된다면  B는 현재 수행중이던 작업에 방해를 받을 것이다. 그렇다고해서 B의 현재 작업이 끝날때까지 기다린다면 A는 그만큼 시간을 버리게 된다. 그래서  A는 해당 처리를 B에게 메세지로 남긴 후 돌아간다. 그러면 B는 자신이 수행하던 처리를 마친 후 메세지를 확인하여 처리한 후 A쪽에 메세지로써 결과를 남긴다. A는 이 메세지를 확인하고 비로소 자신이 맡긴 처리가 잘 수행되었다고 판단한다.


이것이 Actor 모델이며 이러한 처리는 대용량의 데이터를 처리할 때 적합하다. 실시간으로 처리되는 작업은 아니지만, 경우에 따라서는 자원의 효율을 극대화 하여 사용할 수 있다. Facebook이나 Twitter에서 대량의 사용자 메시지를 처리할때 사용한다. Erlang이나 Scala에서 해당 모델을 채용하고 있으며 이런 방식을 메시지 기반의 방식이라고 한다.


2번째 항목은 어떨까? 메모리를 공유하더라도 변경하지 않으면 된다. 

const는 상수화하여 값을 변경할 수 없도록 하고, Scala에서는 변수선언 키워드가 var, val 2가지로 구현되여 val은 const로 선언된다.

또한 Java에서는 class에 private한 영역을 만들어서 getter 메소드는 생성하여 읽기는 가능하지만 setter 메소드는 생성하지 않아 값을 수정할 수 없도록 하는 Immutable 패턴이 자주 사용된다.


3번째 항목을 위해서 어느 한 처리 중에는 끼어들지 않도록 하는 기법들이 생겨났다. 

그 중 하나가 서로 협력하는 스레드가 생겨났다는 것이다. 스레드는 기본적으로 preemptive하므로 non-preemptive한 스레드를 만들자라는 개념이다. fiber, coroutine, Green thread와 같은 기법을 사용하는 Ruby의 Fiber Class나 Python이나 JavaScript의 Generator가 그 예이다.

다른 하나는 다른 처리에게 해당 메모리로 접근하지 말라고 표시하는 Lock, Mutex, Semaphore를 이용하는 것이다. 이 방식에서는 deadlock의 문제를 잘 인식하고 사용해야 할 필요가 있다. 이는 굉장히 까다로운 일이다.


이를 약간 편하게 사용하기 위해 DataBase의 transation 기법을 적용한 Transactional memory 기법이 탄생했다. 해보고 실패하면 다시 처음으로 돌아가고 끝까지 성공하면 변경을 공유하는 것이다. 이는 락을 걸지 않아도 문제가 없이 병행처리가 가능하다. 하지만 다시 고쳐쓰는 작업이란 비용이 많이 드는 작업이다.





이벤트기반과 메세지기반 아키텍처는 어느 한 것만 고집할게 아니라, 시스템의 환경에 맞게 적절히 사용하는게 가장 좋겠다.






참고. 코딩을 지탱하는 기술

'Development > Etc.' 카테고리의 다른 글

type(형)  (0) 2016.02.06
언어별로 문자열 처리  (0) 2016.02.06
전역스코프 동적스코프 정적스코프  (0) 2016.02.06
상속이 is-a 관계여야 하는이유와 delegation  (0) 2016.02.06
언어별 클래스의 의미  (0) 2016.02.06


> 카페


  http://cafe.naver.com/ojsag


> 네이버 SVN


  http://dev.naver.com

  

  * 멤버등록

  * 암호설정


> 이클립스


  * plug-in  

  * SVN Repository

  

https://dev.naver.com/svn/ojsag20


subclipe 설치 > SVN  설정 > checkout


> 소프트웨어 개발 패러다임


구조적     >     정보공학     >     객체지향 >                 Contents Based Development?                 >     SOA     >     ROA

"절차"            "데이터"                "클래스"                                - Controller - Suvlet

    멤버(필드, 메소드)                         - View - html, xml

  - Model - JSON

* library와 Contents의 차이

: library는 그냥 모듈화, Contents는 MVC 모델을 포함하는 모듈화


> 프토토콜


비연결지향 (HTTP)

연결지향(FTP)


> 웹


"비연결지향 프로토콜의 단점을 해결하기 위한 기술"


1. Client Side

쿠키

2. Server Side (서버상태를 저장하기위한 객체 4가지)

PageContext 페이지

HttpServletRequest

HttpSession 웹브라우저

ServletContext 톰캣

3. File

4. DBMS


 > 요청 (Client Side - HTML5 + CSS + JavaScript + jQuery + Ajax)


URL


> 응답 (Server Side - Controller + View + Model Service + Model Entity)


HTML, XML, JSON, Text, ...


> 소프트웨어 공학


95년도 4학년 과정으로 선택과목으로 등장

2000년도 이후 필수과목으로 채택


"품질" - ISO 9126(6가지 품질), IEEE 1471(아키텍처 표준), ISO 52000(테스트 표준)

"객체지향"


> 소프트웨어 위기


"스파게이티 소스"


> 클래스 vs 객체지향


1. 저장위치

- 클래스 : 파일이므로 하드디스크

- 객체 : 파일의 클래스 로더가 클래스를 로딩하여 메모리에 올림. 값을 담기위해 만들어진 구조체.


2. 값의유무


> 객체 라이프 사이클


1. 클래스 정의

2. 객체참조변수 선언

3. 객체생성

4. 생성자호출

5. 주소할당

6. 객체사용

7. 객체소멸


"    Student st = new Student();   "


1. 클래스 정의 : Student. Student는 이미 정의되어 있어야 함.

2. 객체 선언 : st, 

3. 객체 생성 : new, 개발자가 직접 객체를 생성하느냐, Controller에게 객체생성을 위임하느냐(IoC), 


* has a, is a 관계

dependency, association, composition, aggregation


4. 생성자 호출 : (). 

5. 주소할당 heap메모리를 "st" 객체참조 변수에 assignment :  =. call by value, call by reference, call by name(없어짐)

6. 객체사용. polymorphism

7. 객체소멸.  java performance tuning 


java - " fojo, annoation "


> OOSD 기본 개념 7가지


<Object-Oriented Design concepts>


Cohesion 응집도. 하나의 클래스가 하나의 기능에 얼마큼 충실하는지 나타내는 척도. 높을수록 좋음.

Encapsulation. 

Coupling 결합도. 응집도를 높이기위해 클래스를 잘게 나누면, 원래 하나였던 클래스는 서로의 결합도를 높이게 됨. 모듈화의 결정 포인트를 잘 맞춰야 함. 낮을수록 좋음.

*Looser Abstract Coupling

Implementation ingeritance .

Composition

Interface ingeritance

Polymorphism


<java method 5가지>


*Looser Abstract Coupling


---------------------------

client  -->   <<interface>>

Service

^

|

|

ServiceImpl

---------------------------


interface Service {

}


class ServiceImpl implements Service {

}


class Client {

Service s;

}



cf. looser couping

 http://tadhg88.blogspot.kr/



> 클래스 간의 관계

* Is-a

* has-a


> OOSD 원리 3가지

> 디자인 패턴


> 웹 서비스


-----------------------------------------------------

홍창윤 강사님 / 010-3206-4184 / hiroad@naver.com

OJSAG 오라클자바소프트웨어아키테트그룹


'Development > Web' 카테고리의 다른 글

MVC 1  (0) 2015.08.30
서블릿  (0) 2015.08.30
이클립스 스프링 개발환경  (0) 2015.08.27
[JQuery] plug-in top 100  (0) 2015.05.27
[웹서비스] 기초 4 - QnA, Web Client  (0) 2015.05.01
#

#

#


1.  view 

test_view.html 파일


2.  model, view에서 넘어오는 데이터를 저장하는 DTO 클래스 작성

test_model_DTO.java


3. DB 생성 및 테이블 생성

4. model, DTO에서 데이터를 전달받아 실제 데이터베이스와의 작업을 처리하는 DAO 클래스 작성

test_model_DAO.java


5. controller, 사용자의 입력정보를 DTO에 담고, 해당 데이터를 DAO클래스의 관련 메서드에 전송하고

그 결과에 따라 이동할 페이지를 결정하여 제어하는 서블릿 클래스를 작성

test_controller.java


6. 처리에 대한 결과를 출력하는 view 페이지 작성

test_result_view.html


'Development > Web' 카테고리의 다른 글

HTTP와 웹 아키텍처  (0) 2015.11.02
서블릿  (0) 2015.08.30
이클립스 스프링 개발환경  (0) 2015.08.27
[JQuery] plug-in top 100  (0) 2015.05.27
[웹서비스] 기초 4 - QnA, Web Client  (0) 2015.05.01


#

1. 톰캣\conf\server.xml 웹서버 구동과 관련한 설정

2. 톰캣\conf\web.xml  모든 프로젝트에 공통적인 환경

톰캣\common\lib 모든 프로제트에 공통된 라이브러리

3. 프로젝트\WEB-INF\web.xml  프로젝트별로 적용되는 환경설정

4. 프로젝트\WEB-INF\lib 프로젝트별로 적용되는 라이브러리

5. 프로젝트\WEB-INF\classes 프로젝트별로로 적용되는 서블릿 파일을 인식하고 설정에 따라 init()/destroy()메서드를 실행


#  서블릿은 매핑과정이 필요. 2가지로 매핑이 가능

1. 어노테이션

2. web.xml


- web.xml

<servlet>

<servlet-name>ServletHello</servlet-name>    // 서블릿 클래스를 임의의 이름으로 정의하여, 이름을 가지고 사용

<servlet-class>kr.co.test.ServletHello</servlet-class>        // 해당 클래스 

</servlet>


<servlet-mapping>

<servlet-name>ServletHello</servlet-name>

<url-pattern>/ServletHello</url-pattern>

</servlet-mapping>




# 서블릿 라이프사이클

0. 서블릿은 클래스이고 HttpServet을 상속받아서 구현


1. init() 메서드에 의해여 초기화되면서 실행

web.xml이 실행이 되면서 실행되거나 최초 접속하는 클라이언트에 의해 실행

2. service(HttpServletRequest request, HttpServletResponse response) ...

클라이언트 요청으로 실행되며 main()에 해당


- doGet()

- doPost()

3. destroy() 메서드는 웹서버가 종료될 때 실행되며, 메모리 해제를 수행



// 12,3은 서블릿(GenericServet)을 오버라이해서 정의


4. PostConstruct : init 선처리

5. PreDestroy : destroy 선처리


// 4,5는 임의의 메소드명을 내가 지정해주고, 어노테이션으로 명시해줘야함

@PostConstruct

public void initPostConstruct() {}


@PreDestroy

public void destroyPreDestroy() {}


1-1. 

- init(ServletConfig)

- init()





# 초기화 매개변수

: 특정 서블릿이 생성될 때 초기에 필요한 데이터들을 위해(특정 경로 및 아이디 정보) 사용

서블릿도 클래스이므로 컴파일해 사용해야하는데, 매개변수가 바뀔떄마다 컴파일 하지않고 좀 더 효율적인 측면에서
매개변수를 바꾸어 사용할 수 있도록 하기위해 사용


초기화 파라미터 사용 방법

1. web.xml에 기술 후, servlet파일에서는 ServletConfig 클래스를 이용하여 접근이 가능

2. Servlet(클래스)파일에 직접 기술


1.

- 서블릿 클래스 제작

- web.xml에서 서블릿 등록 시, init-param태그를 사용하여 초기화 매개변수를 등록. servlet태그 안에다가 정의

<servlet>

<servlet-name>ServletHello</servlet-name>    

<servlet-class>kr.co.test.ServletHello</servlet-class>   


<init-param>

<param-name>id</param-name>

<param-value>userid</param-value>

</init-param>     

</servlet>


- 서블릿 클래스에서 getInitParameter(),로 가져와서 사용.

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {


String id = getInitParameter("id");

}


ServletConfig 클래스는 HttpServlet에서 상속하고있는데 내 servlet클래스는 이미 HttpServlet을 상속하여 생성하였으므로 따로 생성할 필요는 없고 

바로 사용하면 됨



2. 

ServletConfig를 상속받은 다른 클래스나 ServletConfig 객체 생성 후 매개변수 가져와 사용


@WebInitParam 어노테이션에 초기화 파라미터를 기술한 후,

: @WebServlet(urlPatterns={"ServletHello"}, initParams=[@WebInitParam(name="id,value="aaaa")}) 


protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {


String id = getInitParameter("id");

}



# response 객체, HttpServletResponse

- 에러처리 : sendError, 

- URL  이동 : sendRedirect


# include, forward

- sendRidrect를 수행하면 버퍼가 비워짐. 

- forward나 include를 사용하면 현재 페이지가 가지고 있는 값들을 유지하여 페이지를 이동할 수 있음

- RequestDispatcher 객체를 사용


RequestDispatcher는 ServletContext에서 받아오면 됨

ServletContext context = ServletConfit객체.getServletContext();

RequestDispatcher dispatcher = context.getRequestDispatcher(페이지주소_상대경로);

dispatcher.include(request,response);

dispatcher.forward(request,response);



# 데이터 저장 영역

- Request, Session 객체

- 쿠키데이터 사용


- Request, Session 객체

1. request(servletRequest of HttpServletRequest)

- request.setAttribute(key,value);

- request.getAttribute(key,value);

- request.removeAttribute(key,value);


2. session(HttoSession)

- session.setAttribute(key,value);

- session.getAttribute(key,value);

session.removeAttribute(key,value);


3. application(ServletContext)

 application.setAttribute(key,value);

- application.getAttribute(key,value);

application.removeAttribute(key,value);


- 쿠키데이터 사용

1. Cookie 전송

Cookie cookie = new Cookie(key, java.net.URLEncoder.encode(value, "UTF-8");

cookie.setComment(주석);

cookie.setPath(도메인);

cookie.setMaxAge(유지시간(초단위));

cookie,.addCookie(cookie);


2. 개별 클라이언트의 Cookies폴더에 파일로 저장

3. Cookie 획득

Cookie[] cookies = request.getCookies();

for(int i=0l i<cookies.length; ++i);

if(key.equals(key)) {

String value = cookies[i].getValue();

}

}



# ServletContext

: 특정 데이터를 여러 서블릿클래스에서 다같이 사용할 수 있도록 지정. 여러 서블릿에서 공유하는 정보이므로 web.xml에서 servlet부분보다 위에 기술되어야함


- Context Parameter를 이용하여 web.xml에 데이터를 기술,

- servlet에서 공유하면서 사용


<context-param>

<param-name>id</param-name>

<param-value>aaaa</param-value>

</context-param>


String id = getServlet();



# Servlet 필터

웹상에서 사용자 요청페이지가 실행하기 전/후에 필요에 의해데이터를 가로채채 작업하고자 하는 경우 사용

- 전달받은 데이터를 인코딩하는 경우

- 세션 데이터를 인증하는 경우

- 이벤트나 공지 등 팝업을 추가하는 경우


- Filter 인터페이스를 구현하는 클래스로 작성한 후  

- 프로젝트에 인식을 위해 web.xml에 작성(등록하기)

filter, filer-mapping(필터가 언제 실행될지의 정보) 태그

- Servlet 부분보다 위에 작성해야 함



# Servlet 이벤트

서버가 실행된 이후에 특정 이벤트를 감지하여 그 시점에 작업을 하고자하는 경우

- 컨텍스트가 초기화하는 경우

- 세션이 생기거나 소멸되는 경우 

- 속성이 바뀌는 경우


- 서블릿 이벤트 리스너를 사용

1. ServletContext 객체 초기화/소멸

: ServletContextListener

2. ServletContext객체에 속성 추가/삭제/수정

ServletContextAttributeListener


3. Session

...


4. Request 

...


- 서블릿 이벤트를 등록 : web.xml

: Listener 태그를 사용

'Development > Web' 카테고리의 다른 글

HTTP와 웹 아키텍처  (0) 2015.11.02
MVC 1  (0) 2015.08.30
이클립스 스프링 개발환경  (0) 2015.08.27
[JQuery] plug-in top 100  (0) 2015.05.27
[웹서비스] 기초 4 - QnA, Web Client  (0) 2015.05.01

+ Recent posts