Spring 개발도구와 환경
* 본 포스트의 내용은 [토비의 스프링3] 내용에서 발췌된 것이다.
본 포스트의 내용은 Spring 3.0 을 기반으로 한다.
* 스프링으로 어떤것을 만들수 있는가?
스프링으로 만들수 있는 애플리케이션의 종류에는 제한이 없고 자바를 사용하는 모든 프로젝트에 사용할 수 있다. 하지만, 대부분 자바 엔터프라이즈 환경에서 동작하는 어플리케이션이다 (즉 서버에서 동작하여 클라이언트에게 서비스를 제공) 가장 많이 사용하는 구조는 클라이언트가 웹 브라우저이고, 백엔드 시스템이 DB인 구성이다.
* 개발도구와 환경
1. JavaSE/JDK : JDK 5.0 or higher (JDBC 4.0 API를 사용 하는 경우 JDK6.0)
2. JavaEE/J2EE : J2EE 1.4 or JavaEE 5.0 (J2EE 1.4 의 경우 JDK 5.0에서 사용불가능한 경우가 있으므로 주의)
3. IDE : Eclipse(or STS-SpringSource Tool Suite), NetBeans, IntelliJ IDEA
: STS - 최신 이클립스를 기반으로 주요한 스프링 지원 플러그인과 관련 도구들을 모아서 스프링 개발에 최적화되도록 구성된 IDE. 스프링소스가 제공하는 플로거인 조합이 완료된 STS를 사용하면, 플로그인 업데이트와 플러그인간 호환성 등에 신경쓸 필요가 없으므로 편리. 게다가 tcServer 를 함께 설치할수 있어서 편리.
tcServer) Spring 개발을 담당하는 SpringSource 는 apache httpd 서버와 tomcat 의 개발자들이 있어서 스프링어플리케이션에 최적화된 tcServer 를 개발했다. 기술지원을 받을 수 없는 오픈소스제품과 달리, tcServer를 사용하면 기술지원을 받을 수 있음. (개발자 버전은 무료이지만, 정식 운영서버에서 사용하고 기술지원 받으려면 유료 라이선스 구매 필요)
4. 스프링 관련 Plugin(s)
SpringIDE plugin
SpringIDE는 스프링 개발에 유용한 기능을 제공하는 플러그인의 모음. 스프링 프로젝트 설정파일 생성 위저드, XML 설정파일 에디터, bean의 의존관계 그래프, 네임스페이스 관리 기능 등의 기능과 도구를 제공함.
STS plugin
스프링 개발과 설정파일 편집을 지원하는 SpringIDE에 더해서 스프링 어플리케이션의 서버 배치와 같은 추가 기능을 제공해 준다.
STS 가 추가로 제공하는 기타 플러그인
- M2Eclipse : Maven 지원하는 Elipse plugin, 스프링은 그 자체로 20여개의 세부 모듈로 구성되어 있고 100개 이상의 의존 라이브러리가 있기 때문에 Maven의 의존 관리 기능을 활용하는게 좋다.
- AJDT (AspectJ Development Tool) : Elipse 에서 AspectJ AOP 를 이용한 개발을 지원.
- VMCI (Virtual Machine Core Integration) : VMWare 서버 혹은 워크스테이션과의 연동을 지원하는 플러그인. STS의 VMWare 배치기능에 주로 사용
- 이클립스 표준 플러그인 : 이클립스에서 제공하는 주요 표준 플러그인으로 웹 개발을 지원하는 WTP(Web Tool Platform), EMP(Elipse Modeling Project), Mylyn, DSDP(Device Software Developlemt Platform)
* 스프링 애플리케이션의 배포 단위
1. 독립 웹 모듈 (war) : 가장 일반적
2. 엔터프라이즈 애플리케이션 (ear) : 스프링애플리케이션에서 EJB 모듈을 이용하거나 EJB모듈이 스프링어플리케이션을 이용해야 하면, EJB와 스프링웹 모듈을 엔터프라이즈 애플리케이션으로 통합해서 배포해야 한다.
3. 백그라운드 서비스 모듈 (rar) : rar 는 리소스 커넥터를 만들어 배포할 때 사용하는 방식인데, 스프링어플리ㅔ이션이 UI가 없고, 서버내에서 백그라운드 서비스 처럼 동작할 필요가 있다면 rar 모듈로 만들어 배포할 수 있다.
* 라이브러리 관리와 빌드 툴
스프링은 자체로 20여개의 jar 모듈과 직접 참조하는 100개 이상의 의존 라이브러리가 있다. 이들의 버전관리도 문제지만, 모든 라이브러리가 다 사용되는게 아니므로, 라이브러리를 선정하는 것도 문제이다.
20여개이 모듈중 몇개는 필수모듈이지만 그 외의 모듈은 애플리케이션의 아키텍처와 사용기술에 따라 서택적으로 적용할 수 있다. 또한 스프링 모듈 사이에도 의존관계가 있고, 모듈의 의존 관계는 필수와 선택으로 나뉠 수 잇다.
- Elipse 같은 IDE의 자동 빌드 기능이 있고, 관련 빌더를 추가/확장 하는 것으로 빌드 작업을 간소화 시킬 수 있지만, IDE를 통한 빌드 환경이 아닌 경우에도 일관성 있는 빌드가 가능하도록 만들기 위해서, Maven 이나 Ant 같은 환경에 독립적인 빌드 툴을 함께 사용하는것이 바람직 하다. 그 중 절차적인 스크립트와 비슷한 Ant와 달리 Maven 은 POM을 이용하여 선언적으로 관리할 수 있다. 더 매력적인 점은 Maven의 의존 라이브러리 관리 기능이 Transitive (전이적)이고, 이는 스프링의 모든 모듈이 POM 정보를 가지고 있으므로, 스프링을 통한 라이브러리 관리를 좀더 편리하게 도와준다.
* 관련 web sites
* STS : http://www.springsource.com/downloads/sts
* Ecllipse : http://www.eclipse.org/downloads
* Eclipse Maven Plugin : http://www.eclipse.org/m2e/
출처: http://lefthand.tistory.com/43 [lefthand's note]
Spring 의 정의와 목적
* 본 포스팅 내용은 토비의 스프링3의 8장의 내용을 요약한 것이다.
Spring 이란 무엇인가?
자바 엔터프라이즈 개발을 편하게 해주는 오픈소스 경량급 애플리케이션 프레임워크
창시자 : Rod Johnson
기원 : Expert One-on-One J2EE Design and Development (2003) 의 sample code
- 애플리케이션 프레임워크
일반적으로 라이브러리나 프레임워크는 특정 업무 분야나 한가지 기술에 특화된 목표(예를들면, 웹 계층을 MVC구조로 변경한다거나, 간단한 설정만으로 RDB와 java object를 매칭해주는 ORM기술 제공등)를 가지고 만들어 지지만, 애플리케이션 프레임 워크란 특정 계층이나, 기술, 업무분야에 국한되지 않고 애플리케이션의 전 영역을 포괄하는 볌용적인 프레임워크이다. 애플리케이션 프레임워크는 애플리케이션 개발의 전 과정을 빠르고 편리하며 효율적으로 진행하는데 일차적인 목표를 두는 프레임워크이다.
- 경량급(lightweiight)
스프링 자체가 아주 가볍다거나 작은 규모의 코드로 이뤄졌다는 뜻이 아니다. 스프링은 20여개의 모듈로 세분화 되고 수십만 라인에 달하는 코드를 가진 방대한 규모의 프레임워크이다. 경량급의 의미는 EJB같은 과도한 엔지니어링이 적용된 기술에 대비하여 불필요하게 무겁지 않다는 의미이다.
EJB : 고가의 WAS필요, 난해한 설정파일, 까다로운 패키징, 불편한 deploy 등으로 인한 부담으로 인해 고가의 제품으로 구성된 제대로된 개발환경이 없이 개발이 어려움. 스프링은 tomcat 이나 jetty 에서도 완벽하게 동작한다. 즉, 서블릿 컨테이너만으로 충분하니, EJB컨테이너나 기타 기능을 사용하지 않아도 된다.
(1) 개발환경의 lightweight
(2) 서버 환경의 lightweight
(3) 코드의 상대적인 lightweight
- 자바 엔터프라이즈 개발을 편하게
로우레벨의 트랜잭션이나 상태관리, 멀티스레딩, 리소스 풀링 같은 복잡한 로우레벨 API 를 이해하지 못하더라도 아무런 문제 없이 어플리케이션을 개발할 수 있다.(From Enterprise JavaBeans 1.0 Specification, Chapter 2 Goals)
로우레벨 기술에 신경쓰지 않으면서, 애플리케이션의 핵심인 사용자의 요구사항, 비즈니스 로직을 빠르고 효과적으로 구현하는 것. 즉, 초기에 스프링의 기본 설정과 적용기술만을 잘 이해하고 있으면, 애플리케이션 개발중에는 스프링 관련 Code 에 신경쓸 필요가 없다.
- 오픈소스
스프링은 오픈소스 프로젝트 방식으로 개발되왔다. 지금도 여전히 오픈 소스 개발 모델과 라이선스를 가지고 개발하는 중이다.
라이센스 : Apache Licence Ver 2.0 (스프링을 상업제품에 포함시키거나 비공개프로젝트에서 사용해도 된다. (수정자유롭고 수정된 소스 공개 필요없음)
Spring 의 Goal
- 엔터프라이즈 개발의 복잡함
2000년대 초반 80% 이상의 자바 enterprise project 가 실패했다. 가장 대표적인 이유는 엔터프라이즈 시스템 개발이 너무 복잡해서 이다.
왜 복잡한가? 비즈니스 로직 이외에도 기술적으로 고려해야 할 사항들이 많다.(타시스템 과의 연계, 다양한 형태의 클라이언트 접속을 위한 리모팅 기술, 분산 트랜잭선의 지원, 보안 등) 또한 비즈니스 로직 자체도 점점 복잡해지고 잦은 변경이 요구된다)게다가 이런 엔터프라이즈 기술의 복잡함과 비즈니스 로직의 복잡함이 한데 얽혀서 복잡함이 배가된다.
- 복잡함을 해결하려는 도전
근본적으로 엔터프라이즈 기술의 복잡함과 비즈니스 로직의 복잡함은 줄일수 없다. 그러나 이 두가지 성질이 다른 복잡함을 분리해 낼수 있다. EJB도 이 목표를 지향하여 선언전 트랜잭션이나 선언적 보안, 컨테이너를 통한 리모팅 기술의 적용, 컴포넌트 단위의 배치, JNDI 를 통한 서비스 검색지원, 서비스 오브젝트의 풀링, 컴포넌트의 생명주기 관리등을 수행하여 이 목표를 달성하려 하였으나, 이를 위해 EJB라는 환경과 스펙에 종속되는 코드로 만들어야 하는 더 큰 복잡함을 안게되어 실패하였다. 게다가 EJB라는 틀 안에서 특정클래스를 상속하게 함으로 자바 언어의 원래 장점마저 상실하고 객체지향적인 특성을 잃어버진 서비스 스크립트성 코드로 변질돼 갔다.
스프링은 EJB와는 다르게 비침투적(non-invasive)기술을 적용하였고, 이는 코드상에 스프링과 관련된 규약과 코드가 등장하지 않는 것을 의미한다. 즉, 스프링이 코드에 불필요하게 등장해서 복잡함을 가중시키지 않는다.
- 복잡함을 상대하는 스프링의 전략
** 기술적 복잡함은 아래와 같이 서비스의 추상화와 AOP 로 상대한다.
1. 서비스의 추상화
트랜잭션 추상화, OXM 추상화, 데이터 액세스에 관한 일관된 예외변환 기능, 데이타 액세스 기술에 독립적인 트랜잭션 동기화 기능 등. 기술적인 복잡함은 추상화를 통해 로우레벨의 기술 구현 부분과 기술을 사용하는 인터페이스를 분리하고, 환경과 사용기술에 독립적인 접근 인터페이스를 제공한다.
2. AOP (Aspect Oriented Programming)
비즈니스 로직 전후로 경계가 설정되어야 하는 트랜잭션, 보안적용, 예외처리, 로깅, 감사 등 기술과 비즈니스 로직의 혼재는 최대한 제거해도 완전히 해결할 수 없으며, 이를 해결하기 위한 스프링의 전략이 AOP 이다. AOP는 최후까지 애플리케이션 로직에 남아있는 기술관련 코드를 깔끔하게 분리해서 별도의 모듈로 관리하게 해주는 강력할 기술이다.
** 비즈니스 로직의 복잡함을 상대하는 전략은 객체지향과 DI이다.
1. OOAD (Object Oriented Analysis & Design)
복잡함을 단순화 할 수 있는 것은 객체지향 기술 자체이며, 스프링은 환경 종속적이지 않고 비침투적인 기술이므로 핵심로직을 다루는 코드에는 스프링이 드러나지 않는다. 따라서 객체지향언어의 장점을 살려 로직의 복잡함을 효과적으로 다루어야 한다.
2. DI (Dependency Injection)
DI는 특별한 기술이라기 보다는 유연하게 확장가능한 오브젝트 설계를 하다보면 자연스럽게 적용하게 되는 객체지향 프로그래밍 기법이다. 스프링은 단지 그것을 더욱 편하고 쉽게 사용하도록 도와줄 뿐이다. DI는 적용하려다 보면 자연스럽게 확장성이 좋은 설계로 이끌어진다. 즉, 바뀔 수 있는 것은 무엇인가? 무엇이 성격이 다른가? 를 지속적으로 고민하게 되고 대상이 되는 Object는 DI를 적용해 분리하고, 인터페이스를 도입하고, DI로 관계를 연결해 주게 되므로 DI를 열심히 적용하다 보면 객체지향 설계의 원칙을 잘 따르고 그 장점을 살린 설계가 나올수도 있다.
출처: http://lefthand.tistory.com/42 [lefthand's note]
Singletone Pattern & Spring IoC Container
* 본 포스트의 내용은 [토비의 스프링3] 내용에서 발췌된 것이다.
* 내용
싱글톤 패턴으 GoF 의 디자인 패턴중 하나다. 디자인 패턴 중에서 가장 자주 활용되는 패턴이기도 하지만, 가장 많은 비판을 받는 패턴이기도 하다. 싱글톤 패턴은 어떤 클래스를 어플리케이션 내에서 제한된 인스턴스 수, 주로 하나만 존재하도록 강제하는 패턴이다. 이렇게 하면 이 클래스의 오브젝트는 애플리케이션 내에서 전역적으로 접근이 가능하다. 단일 오브젝트만 존재해야 하고, 이를 애플리케이션의 여러 곳에서 공유하는 경우에 주로 사용한다.
* Java 에서 Singleton 을 구현하는 일반적인 방법
- 생성자를 private 으로 설정하여 클래스 밖에서는 오브젝트를 생성하지 못하게 함
- 생성된 singleton 오브젝트를 저장할 수 있도록 클래스 내에 자신과 같은 타입의 static field 정의
- static factory method 인 getInstance()를 만들어 최초 호출 시점에만 오브젝트 생성하고 static field 에 저장.
public class UserObject {
private static UserObject INSTANCE;
...
private UserObject(..) {
..
}
public static synchronized UserObject getInstance() {
if (INSTANCE == null) INSTANCE = new UserObject(..);
return INSTANCE;
}
}
* Java 에서 위와같이 singleton을 구현하는 경우 singleton pattern 의 한계
- private 생성자를 갖고 있기 때문에 상속할 수 없다.
객체지향의 상속과 다형성 적용 불가
- 테스트가 어렵다.
싱글톤은 만들어지는 방식이 제한적이므로 테스트에서 Mock Object 로 대체하기가 힘들다.
- 서버환경에서는 singleton 이 하나만 만들어지는 것을 보장하지 못한다.
서버에서 class loader 를 구성하는 방법에 따라서 하나 이상의 오브젝트가 만들어 질 수 있다.
- 싱글톤의 사용은 전역 상태를 만들 수 있기 때문에 바람직 하지 못하다.
singleton의 static method 를 이용하여 어떤 client 라도 접근/사용할 수 있으므로, 전역상태(global status)로 사용되기 쉽다. 아무 객체나 자유롭게 접근/수정/공유하는 전역상태는 OOP에서는 권장되지 않는다.
* Spring Framework 에서의 singleton
Spring은 서버 환경에서 singleton으로 service object 를 사용하는 것을 지지한다. 다만, java 의 기본적인 singleton 구현방식은 상기의 단점이 있으므로, Spring Framework 자체에서 singleton 형태의 object를 만들고 관리하는 기능인, singleton registry 를 제공한다.
Spring의 ApplicationContext 는 Singleton을 저장하고 관리하는 Singleton registry 이다.
* Spring Registry
Spring 은 디폴트로 내부에서 생성하는 Bean object 를 singleton으로 만든다. 이것은 디자인 패턴의 싱글톤과 비슷한 개념이지만, 구현방법은 확연히 다르다. 즉, Spring container 에서 object 를 singleton registry 에 관리하며 singleton으로 동작하도록 제어한다.
왜 Spring은 singleton으로 bean 을 생성하는 것일까?
하나의 요청(Request)를 처리하기 위해서는 데이타 액세스 로직(DAO), 서비스 로직, 비즈니스 로직, 프리젠테이션 로직등 다양한 기능을 담당하는 오브젝트들이 계층형 구조로 이루어 진다. 매번 클라이언트 요청이 올때마다, 각 로직을 담당하는 오브젝트들을 새로 만들어 사용한다면, 아무리 Java가 오브젝트 생성과 GC(Garbage Collection) 성능이 좋아졌어도 서버가 부하를 감당하기 심들다. 이 때문에 엔터프라이즈 분야에서는 서비스오브젝트 라는 개념을 사용해 왔는데 Servlet 은 Java 엔터프라이즈 기술의 가장 기본이 되는 서비스 오브젝트라고 할수 있다. Servlet은 대부분 멀티스레드 환경에서 Singleton으로 동작한다. 즉, Servlet 클래스 당 하나의 오브젝트만 만들어 주고, 사용자의 요청을 담당하는 여러 스레드에서 하나의 오브젝트를 공유해서 사용한다.
Singleton registry 덕분에 singleton 으로 동작해야 할 어떤 클래스라도 평범한 java class 로 작성될 수 있다. 즉, public 생성자를 가질 수 있으며 static method 를 노출할 필요도 없다. 이것은 테스트 환경에서 자유롭게 object 를 만들 수 있고 또한 OOP의 장점을 그대로 가진다.
* Spring 에서 Singleton object 로 사용할 클래스 설계시 주의점
Spring 에서 singleton 이 멀티스레드 환경에서 서비스 오브젝트에 사용되는 경우에는 상태정보를 내부에 갖고 있지 않은 stateless 로 만들어야 한다. 이 경우, 각 요청에 대한 정보나 생성된 정보는 메소드 파라미터나 메소드 안의 로컬변수 혹은 리턴값 등으로 처리해야 한다. 싱글톤이라해도 메소드 안에서 생성되는 로컬변수는 method가 호출될 때마다 매번 새로 할당되므로 싱글톤이라 해도 여러 스레드가 변수의 값을 덮어쓸 일은 없다.
public class UserDao {
private ConnectionMaker connectionMaker; <-- (1)
private Connection c; <-- (2)
private User user; <-- (2)
public User get(String id) throws ClassNotFoundException, SQLException {
this.c = connectionMaker.makeConnection();
....
this.user = new User();
this.user.setId("...");
...
return user;
}
}
UserDao 는 IoC container 에 의해서 singleton object 로 생성/사용된다고 가정해 보자.
이런 경우, (2)번과 같이 멀티스레드 환경에서 변경될 수 있는 값을 클래스의 인스턴스 변수로 생성하는 경우, 문제가 발생한다. 따라서 Spring 의 singleton bean 으로 사용되는 클래스를 만들때는 (2)번의 경우는 method 내 로컬 변수로 사용하거나 파라미터로 주고 받으며 사용해야 한다.
단, 이 경우에도 클래스 인스턴스 변수로 사용가능한 경우가 있는데 이는 (1) 과 같다.
(1)은 자신이 사용하는 다른 singleton bean 을 저장하려는 용도라면, 인스턴스 변수로 사용해도 좋다. 스프링이 초기화 되고 나면, 이후에 수정되지 않는 경우라면, 멀티스레딩 환경에서 사용해도 문제없다
* Spring bean 의 스코프
scope : 스프링이 관리하는 오브젝트, 즉 빈의 생성/존재/소멸되는 범위
singleton : 스프링 bean 의 기본 scope 는 singleton 이다. 컨테이너 한개에 한개만 생성되며 강제로 제거하지 않는 한 컨테이너가 존재하는 동안 계속 유지된다.
prototype : 컨테이너에 빈을 요청할 때마다 매번 새로운 오브젝트를 만들어준다.
request : 웹을 통해 HTTP 요청시마다 생성되는 scope
session : 웹의 세션과 유사한 scope
출처: http://lefthand.tistory.com/41 [lefthand's note]
POJO (Plain Old Java Object)
* 본 포스트의 내용은 [토비의 스프링3] 내용에서 발췌된 것이다.
POJO (Plain Old Java Object) ?
1. 특정 규약(contract)에 종속되지 않는다.
Java 언어와 꼭 필요한 API 외에 종속되지 않는다. EJB2 의 EntityBean 상속이나 Struts 1 의 ActionForm 상속등 규약에 종속되지 않아야 한다.
2. 특정 환경에 종속되지 않는다.
EJB3 의 JNDI 서버 서비스의 의존이나 특정 벤더의 서버나 기업프레임워크안에서만 동작 가능한 코드가 아니다.
3. 객체지향원리에 충실해야 한다.
특정 기술규약과 환경에 종속되지 않은 Java Object 가 모두 POJO라 할수는 없다. 객체지향 개념이 녹아있지 않은 것만 POJO 이다.
Why POJO?
1. 코드의 간결함
비즈니스 로직과 특정 환경/low 레벨 종속적인 코드를 분리하므로 단순하다.
2. 자동화 테스트에 유리
환경 종속적인 코드는 자동화 테스트가 어렵지만, POJO 는 테스트가 매우 유연하다.
3. 객체지향적 설계의 자유로운 사용
특정 규약 종속적인 객체의 경우 특정 상속을 미리 지정해서, 단일상속만 제공하는 JAVA 언어로서는 더이상 객체지향적 설계를 하는데 제약을 가져오는 경우가 있으나, POJO 는 아무런 규약이나 규제가 없으므로 OO 설계에 매우 자유롭다.
What is POJO Framework?
POJO 프로그래밍이 가능하도록 기술기반을 제공하는 Framework.
1. Spring Framework
엔터프라이즈 기술에만 최소한으로 관여하고 비즈니스 로직을 담당하는 POJO에서는 관여하지 않는다.
2. Hibernate
Spring 의 핵심 기술?
기술과 비즈니스로직을 분리하고 POJO방식의 어플리케이션 개발을 가능하게 한다는 스프링의 목적을 쉽게 이루려면 스프링과 같은 POJO 프레임워크가 필요하다.
POJO 프로그래밍을 손쉽게 할 수 있도록 지원하는 세가지 가능기술(Enabling technology)
(1) IoC/DI (Inversion of Control / Dependency Injection)
IoC/DI 는 스프링의 가장 기본의 되는 기술이자 스프링의 핵심 개발원칙이다. 나머지 두가지 기술인 AOP 와 PSA도 IoC/DI에 바탕을 두고 있으며, 3대기술은 아니지만 자주 등장하는 템플릿/콜백 패턴의 적용도 IoC/DI가 핵심원리다.
(2) AOP (Aspect Oriented Programming)
핵심 관심사를 분리하여 프로그래매 모듈화를 향상시키는 프로그래밍 스타일이다. AOP는 객체를 핵심 관심사와 횡단 관심사로 분리하고, 횡단 관심사를 관점(Aspect)라는 모듈로 정의하고, 핵심 관심사와 엮어서 처리할 수 있는 방법을 제공한다. 스프링은 자체적으로 프록시 기반의 AOP를 지원하며, 로깅, 트랜잭션, 보안 이런것들이 전반적으로 처리하는데 사용됨.
(3) PSA (Portable Service Abstraction)
인터페이스가 다른 다양한 구현을 같은 방식으로 사용하도록 중간에 인터페이스 어댑터 역할을 해주는 레이어를 하나 추가하는 방법
출처: http://lefthand.tistory.com/40 [lefthand's note]
IoC(Inversion of Control) / DI(Dependency Injection)
* 본 포스트의 내용은 [토비의 스프링3] 내용에서 발췌된 것이다.
What is IoC (Inversion of Control)?
프로그램의 제어 흐름 구조가 뒤바뀌는 것.
일반적으로, main() 같은 프로그램이 시작되는 지점에서 다음에 사용할 오브젝트를 결정하고, 생성하고, 만들어진 오브젝트내의 메소드를 호출하고 하는 작업이 반복된다. 이런 프로그램 구조에서 각 오브젝트는 프로그램 흐름을 결정하거나 사용할 오브젝트를 구성하는 작업에 능동적으로 참여한다. 즉, 모든 종류의 작업을 사용하는 쪽에서 제어하는 구조이다.
제어의 역전이란, 제어 흐름의 개념을 거꾸로 뒤집는 것이다. 오브젝트는 자신이 사용할 오브젝트를 스스로 생성하거나 선택하지 않는다. 또한 자신도 어떻게 만들어지고 어디서 사용되는지 알수 없다. 모든 제어 권한을 자신이 아닌 다른 대상에게 위임한다. 프로그램의 시작을 담당하는 main()같은 엔트리 포인트를 제외하면 모든 오브젝트는 이렇게 위임받은 제어 권한을 갖는 특별한 오브젝트에 의해 결정되고 만들어 진다. 단지 스프링에서 사용되는 개념이 아니고, 매우 폭넓게 사용되는 프로그래밍 모델이다.
- 작업을 수행하는 쪽에서 Object 를 생성하는 제어 흐름의 개념을 거꾸로 뒤집는다.
- IoC 에서는 Object 가 자신이 사용할 Object 를 생성하거나 선택하지 않는다.
- 또한 Object 는 자신이 어떻게 생성되고 어떻게 사용되는지 알 수 없다.
- 모든 Object 는 제어 권한을 위임받는 특별한 Object 에 의해서 만들어 지고 사용된다.
What is DI (Dependency Injection) ?
- Spring이 지원하는 IoC방식을 좀더 명확히 설명.
- dependent object(의존 오브젝트) : 사용 대상이 되는 오브젝트
- 의존 오브젝트와 그것을 사용할 주체, 보통 클라이언트라고 부르는 오브젝트를 런타임시에 연결해 주는 작업.
의존관계주입의 조건
- 클래스 모델이나 코드에는 런타임 시점의 의존관계가 드러나지 않는다. (즉, 인터페이스에만 의존)
- 런타임 시점의 의존관계는 컨테이너나 팩토리같은 제 3의 존재가 결정한다.
- 의존관계는 의존 오브젝트 레퍼런스를 외부에서 제공(주입)해줌으로 만들어진다.
IoC 개념이 녹아 있는 Example
1. servlet 과 container.
: 서블릿에 대한 제어권한을 가진 컨테이너가 적절한 시점에 서블릿 클래스의 오브젝트를 만들고 그 안의 메소드를 호출한다.
2. Template Method Pattern (Design Pattern)
: http://lefthand.tistory.com/34
역시 제어권을 상위 템플릿 메소드에 넘기고 서브 클래스는 필요할 때 호출되어 사용되는 개념.
3. Framework
: 라이브러리를 사용하는 어플리케이션은 어플리케이션의 흐름을 직접 제어하지만, 프레임워크는 애플리케이션 코드가 프레임워크에 의해서 사용된다. 보통 프레임워크 위에 개발한 클래스를 등록해 두고, 프레임워크가 흐름을 주도하는 중에 개발자의 어플리케이션 코드를 사용하도록 만드는 방식이다. 즉, 제어의 역전 개념이 적용되어 있어야 한다.
스프링 IoC의 용어 정리
* bean
: 스프링에서 제어권을 가지고 직접 만들고 관계를 부여하는 오브젝트를 bean 이라 부른다. 자바빈, EJB의 빈과 비슷한 오브젝트 단위의 애플리케이션 컴포넌트를 말한다. 하지만 스프링을 사용하는 애플리케이션에서 만들어지는 모든 오브젝트가 빈은 아니다. 스프링의 빈은 스프링 컨테이너가 생성과 관계설정, 사용등을 제어해주는 오브젝트를 가리킨다.
* bean factory
스프링의 IoC를 담당하는 핵심 컨테이너를 가리킨다. 빈을 등록/생성/조회/반환/관리한다. 보통은 bean factory 를 바로 사용하지 않고 이를 확장한 application context 를 이용한다. BeanFactory 는 bean factory 가 구현하는 interface 이다. (getBean()등의 메소드가 정의되어 있음)
* application context
bean factory를 확장한 IoC 컨테이너이다. 빈의 등록/생성/조회/반환/관리의 기능은 bean factory 와 같지만, 여기에 spring 의 각종 부가 서비스를 추가로 제공한다. ApplicationContext는 application context가 구현해야 하는 interface이여, BeanFactory 를 상속한다.
* 설정정보/설정 메타정보 configuration metadata
application context 혹은 bean factory 가 IoC를 적용하기 위해 사용하는 메타정보이다. 스프링의 설정정보는 컨테이너에 어떤 기능을 세팅하거나 조정하는 경우에도 사용하지만 주로 bean 을 생성/구성하는 용도로 사용된다.
* container (IoC container)
IoC 방식으로 bean을 관리한다는 의미에서 bean factory 나 application context 를 가리킨다. (spring container = application context) application context는 그 자체로 ApplicationContext 인터페이스를 구현한 오브젝트를 가리키기도 하는데, 하나의 애플리케이션에 보통 여러개의 ApplicationContext Object가 만들어진다. 이를 통칭해서 strping container라고 부를 수 있다.
* spring framework
spring framework 는 IoC container, application context 를 포함해서 spring이 제공하는 모든 기능을 통칭할때 주로 사용된다.
Spring 에서 IoC/DI 활용 방법:
* DI를 이용한 핵심기능의 변경
디자인 패턴의 전략패턴에 해당하는 의존 대상의 implementation 의 변경에 사용함.
A->B 에서 A 기능 일부를 B에게 위임하는 경우 필요에 따라 B의 구현방식을 통째로 B1, B2, B3로 변경한다.
ex) DAO의 구현을 JDBC, JPA, Hibernate, JDO, iBatis 등으로 변경
ex) 사용자 등급 결정 정책을 DI로 새오운 클래스로 변경
* 핵심기능의 동적인 변경
DI 도 runtime 시에 동적으로 의존 Object 를 연결해 주긴 하지만, DI되면 정적인 관계가 형성된다. 하지만 DI 를 잘 이용하면, 애플리케이션이 동작하는 중간에 의존 대상을 dynamic 하게 변경할 수 있다.
ex)사용자 등급에 따른 DataSource의 선택
DAO->DataSource 일때, DAO 하나가 여러개의 DataSource 에 의존하게 만들어, 현재 접속한 사용자의 등급에 따라서 다른 DataSource 를 DAO가 사용하도록 한다.
ex) 사용자 별로 독립 Object 만들고 서비스 Object가 이를 DI 받아서 사용하는 경우.
* 부가기능의 추가
DI의 다른 활용방법은 핵심기능은 그대로 두고 부가기능을 추가하는 것이다. Decoration Pattern 의 경우임.
ex) 트랙잭션 기능 부여.
핵심 기능은 그대로 두고 결과나 전달 파라미터를 조작할 수 있고, 파라미터나 리턴 결과를 활용해 로깅이나 보안처리 같은 부가적인 작업을 수행 할 수도 있다. 이베트 발생 처리 등등.
* 인터페이스의 변경
클라이언트가 사용하는 실제 인터페이스와 실제 오브젝트 사이의 인터페이스가 일치하지 않는 경우에도 DI 는 유용하다. A->B인터페이스 고, C는 B인터페이스를 구현하지 않았더라도 A가 DI를 통해 B를 사용하므로, B의 구현 오브젝트에서 C를 호출해 주는 어댑터 처럼 동작하면 된다.
PSA (Portable Service Abstraction): 이를 좀 더 일반화 하여 아예 인터페이스가 다른 다양한 구현을 같은 방식으로 사용하도록, 중간에 인터페이스 어댑터 역할을 해주는 레이어를 하나 추가하는 방법이다.
* 프록시
laze loading(필요한 시점에서 실제 사용할 오브젝트를 초기화, 준비) 할때, 또는 원격 오브젝트를 호출할 때 마치 로컬에 존재하는 오브젝트 처럼 사용할 수 있도록 할때 프록시가 필요하고, 이 경우 DI를 필요로 한다. Spring이 지원하는 리모트 기술은 EJB원격호출, 웹 서비스, REST, HTTP 등 다양하다.
* 템플릿과 콜백
템플릿/콜백 패턴은 DI의 특별한 적용방법이다. 반복적으로 등장하지만, 항상 고정적인 작업 흐름과 그 사이에서 자주 바뀌는 부분은 분리해서 템플릿과 콜백으로 만들고 DI원리를 응용해 적용한다. Spring 이 기본으로 제공하는 20여가지의 템플릿/콜백외에도 직접 응용할 수 있어야 한다.
* Singleton 과 Object Scope
DI를 프레임워크로 이용한다는건 DI대상 오프젝트를 컨터이너가 관리한다는 의미이다. 오브젝트의 생성부터 관계설정, 이용, 소멸에 이르기까지 모든 과정을 DI컨테이너가 주관하기 때문에, 그 오브젝트의 스코프를 자유롭게 제어할 수 있다. 스프링의 DI는 기본적으로 singleton으로 오브젝트를 만들어서 사용하게 하고, 컨테이너가 알아서 싱글톤을 만들고 관리하므로 클레스 자체는 싱글톤을 고려하지 않아도 된다. 물론, 스프링에서는 싱글톤 외에도 다양한 스코프를 갖는 오브젝트를 만들어 DI 할 수 있다.
* 테스트
DI의 또다른 중요한 용도는 Test 이다.테스트 할 대상이 사용하는 오브젝트를 테스트 목적으로 만들어진 Mock 오브젝트로 대체하면 테스트가 매우 용이하다.
출처: http://lefthand.tistory.com/39 [lefthand's note]
apache module configuration
httpd.conf 에 LoadModule 되는 (혹은 static library로 포함되는) apache module 은 각각의 설정을 저장하기 위해 config 객체를 사용할 수 있다. 이 config 객체를 사용하는 경우 각 서버(virtual server 와 기본서버)별로 각각 생성된다. apache module config 객체를 사용하기 위해서, apache module 은 모듈 정의 부분에서 function을 지정할 수 있으며, 편의상 이하 이 function 을 create_server_config라 임의로 지칭하기로 한다.
[create_server_config function 호출 시기]
static void * (*pf_create_server_config) (apr_pool_t *p, server_rec *s);
1. apache start/stop 시 전역적으로 최소 1번 호출됨.
: default module config 객체를 생성과 초기 설정이 이루어짐.
apache 서버가 default server 이외에 1개 이상의 virtual server 를 구성하는 경우, 각 Virtual Server 에서 작성된 apache module 의 configuration command 를 사용하지 않으면, 이때 생성된 config 내 용이 각각의 virtual server module config 객체로 복제 된다.
2. 각 Virtual server 별로 overriding 가능
: 만약 virtual server 내에 configuration command 를 하나 이상 정의하면, 그때는 default module config 객체를 복제하지 않고, create_server_config 함수가 virtual server 를 위해 다시 호출된다.
! CAUTION1) create_server_config 에 전달되는 server_rec * 은 1번의 경우, host 정보가 null 로 들어오며, 2번의 경우에는 각 virtual server 의 설정 값을 갖는다.
!CAUTION2) create_server_config 는 configuration commend 호출 전에 호출돤다.
!CAUTION3) 전달되는 pool 은 pConf 이다. (apache pool hiarachy 참고)
[ap_hook_post_config 이용]
static int (*pf_post_config) (apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s);
apache module 은 여러가지 hook 을 제공하며, 사용자들이 기능을 추가/변경 할수 있도록 한다. module config 를 위해서 command 를 다 읽은 후에 설정 내용을 변경/수정 할수 있도록 ap_hook_post_config 를 제공하며, 여기에 기능을 추가 할 수 있다.
각 Virtual server 별로 설정을 달리 해야 할 것들이 있다면 여기서 수행하면 된다.
!CAUTION1) server_rec * 구조체에는 default server 와 Virtual Server 들을 모두 참조가능하도록 default server 의 server_rec 이 전달되며, s = s->next 값으로 모든 서버들의 설정을 검토할 수 있다.
!CAUTION2) 전달되는 pool 은 pConf 이다. (apache pool hiarachy 참고)
module config 는 각 서버당 1개씩 생성되고, 프로세스 간 공유되므로, 기본적으로 최초 apache 로딩 시 값 설정 후에는 실제 서비스에서 변경하지 않는 것이 좋다. 만약 module config 를 변경해야 할 일이 있다면, pConf 에 mutex 를 생성하여 사용해야 한다.
개인적으로는, mutex 사용보다는 메모리가 충분하다면, apache 가 MPM 이 prefork 방식인 경우, 각 process 별로 메모리를 전역으로 복제/갱신하여 사용하는 것이 더 나을 수 있다. (물론 메모리 크기와 갱신 주기 등등 여러가지를 고려해야 함)
출처: http://lefthand.tistory.com/38 [lefthand's note]
Rewrite & Redirect
아파치 설정의 Rewrite 와 Redirect 에 대해서 간략히 정리한다.
301 Redirect : Permanent Redirect, 브라우저에서 해당 내용을 cache 하여 다음에 요청시에 직접 변경된 주소로 접속한다.
302 Redirect : Temporary Recirect,
<mod_alias.c>
base 모듈(apache 설치시 디폴트로 함께 설치되는 모듈)
default - 302 Redirect (Temporary)
Redirect
RedirectMatch
<mod_rewrite.c>
Extension 모듈 (apache 설치 시 선택하여 설치해야 하는 모듈, static, dynamic 모두 가능)
!main server의 설정이 각각의 virtual host 에 상속되지 않는다. virtual host 별로 각각 설정해 줘야함.
default - 302 redirect
옵션 :
[NC] no-casesensitive
[NE] no-escape
[R] 주소창이 변하기 않기를 원할때
[L] last 적용
[OR] 컨디션의 or
...
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond
RewriteRule
</IfModule>
RewriteRule ^products/([0-9][0-9])$ /products/$1/ [R]
$1, $2, .. $9 첫번째그룹, 두번째 그룹...
출처: http://lefthand.tistory.com/31 [lefthand's note]
blocking/non-blocking socket
* Blocking Socket
- default 값 (socket() 으로 생성되는 기본값)
- connect : connection completion 까지 block
- read : 버퍼에 읽을 값이 없으면 block
- write : 버퍼가 꽉 차서 쓸 수 없으면 block
- accept : backlog queue 에 값이 없으면 block
: blocking 소켓 통신에서 어떤 에러 결과든지 메소드는 자동으로 에러를 규명하는 코드를 같이 리턴한다. 에러는 네트워크 종료, 닫힌 소켓, 아이오 에러 등이 될 수 있다
동기식 통신을 사용한다면 blocking 통신이 더 낫다.
* Non-blocking Socket
- connect : connection 요청 후 즉시 return. connection 이 완료되었는지 보증 안됨.(getsockopt 로 확인)
- read : 버퍼에 읽을 값이 없으면 -1 return (errno : EWOULDBLOCK or EAGAIN)
- write : 버퍼가 꽉 차서 쓸 수 없으면 -1 return (errno :EWOULDBLOCK or EAGAIN)
- accept : backlog queue 에 값이 없으면 -1 return (errno : EWOULDBLOCK or EAGAIN)
: 할수 있는 일이 없으면, 종료하고, 다른 작업(?) 을 할 수 있고, 할 수 있는 일이 있을 때만 작업한다.
비동기식 통신에서는 소켓이 묶이는 것을 피하기 위해 non-blocking 통신이 필요하다.
* Nonblocking socket 설정
int flag, sock_fd;
sock_fd = socket (AF_INET, SOCK_STREAM, 0);
flag = fcntl (sock_fd, F_GETFL, 0);
fcntl ( sock_fd, F_SETFL, flag|O_NONBLOCK );
* timeout 설정
출처: http://lefthand.tistory.com/29 [lefthand's note]
Linux 에서 사용자별 메모리 문제 발생시 대응 방법
본 문서에서는 Linux 에서 OOM(Out-Of-Memory) 발생 시 대응 방법들이다.
1. 문제 발생 방지
[설정파일을 통한 limit (/etc/security/limits.conf)]
: 각 사용자 혹은 그룹등에 리소스 사용 제약사항을 걸어두면, 자원의 무제한 사용을 막을 수 있다. 특정 사용자 혹은 그룹등이 사용하는 프로세스의 메모리가 예상 가능하며, 계속 증가되지 않는다고 가정하는 경우 사용하면 유용하다.
!) 현재는 (kernel : 2.6.31) 메모리 관련 item 으로는 rss (resident set size:real 할당 메모리)가 있지만 이 값에 설정한다고 해서, memory 사용을 막지는 못한다. 제대로 동작된다고 보여지지 않는다.
!) 메모리 제한을 위해서, 사용할 수 있는 방법은 as(address space) 에 limit 을 걸면 잘 동작한다.
as 는 Virtual Memory Address Space 이다. 따라서 내가 10M 정도의 제약을 가하고 싶다면 10*1024 = 10240 값을 주면 된다. (단위는 KB 이다.) 주의할 점은, 이 제약조건은 사용자 혹은 그룹등이총 사용하는 리소스가 아니라, 사용자 혹은 그룹등에서 사용하는 프로세스 당 제약 조건이다.
예) * soft as 10240
* hard as 10240
soft 는 기본적으로 적용되는 limit 항목이며, hard 까지 limit 상승이 가능하다. 프로그램 내부에서는 기본설정된 값(soft limit 조건)보다 더 큰 값을 사용해야 하는 경우 최대 hard 에 설정된 값까지 limit 을 증가시킬 수가 있지만, 이를 위해서는 root 권한이 필요하다.
!) /etc/security/limits.conf 값은 shell 이 생성될 때 적용되며, 기존 shell 에는 적용되지 않는다. 따라서 기존 shell 을 이용할 때는 명령창에 ulimit -v 10240 으로 동일하게 적용학 수 있다.
2. 원인 분석
[문제 발생 소스를 수정 가능한 경우]
: 문제의 재현스텝이 불분명하고, 발생 지점을 확인하기 어렵지만, 문제의 소스를 수정할 수 있는 경우, 기존에 짜여진 소스는 그대로 두고 memory hook 을 정의해서 문제 발생 지점을 확인 할 수 있다.
linux memory hook 사용 법
[문제 발생 소스를 수정 불가능한 경우]
: 문제의 재현스텝이 불분명하고, 발생 지점을 확인하기 어렵우며, 문제의 소스를 수정할 수 없는 경우, 컴파일을 다시 할 수 있다면 gcc -g 옵션을 추가해서 재 컴파일 한다. 디버깅 옵션이 설정되지 않은 상태에서 컴파일 옵션 마저 변경할 수 없는 경우라면, 더이상 진행 불가하다. 기존 바이너리가 -g 옵션으로 컴파일 되었거나, 컴파일을 -g 옵션으로 다시 할 수 있다면, 1번의 /etc/security/limits.conf 파일에 core 파일 생성을 unlimited 로 추가한다.
* - core unlimited
linux reboot 후에도 위의 옵션이 먹지 않는다면, /etc/profile 을 확인하자.
아래의 내용이 있다면, 주석처리한다.
#ulimit -S -c 0 > /devnull 2>&1
만약, 프로그램 동작 중, 다시 OOM 상황이 발생하는 경우, 1번에서 제한한 limit 값에 도달하면, 운 좋으면 core 를 떨어뜨리고 죽을 것이다. 여기서 운이 좋다는 것은 프로그램이 메모리를 사용하기 전에 NULL check 를 하지 않는 경우이다. 만약 프로그램이 메모리 사용전 NULL check 를 꼼꼼히 한다면, 프로그램은 오류 상태로 정상 종료 할 것이다.
[Tool 을 통한 분석]
프로그램이 -g 옵션으로 컴파일 되어 있고, 성능 이슈가 크지 않다면, valgrind 의 여러가지 툴을 이용해서 메모리 증가 지점에 대한 상세한 로그를 받을 수 있다. 단, valgrind 등 툴을 사용하여 프로세스를 띄우는 경우, 프로파일링을 위해서 많은 자원과 시간이 소모되므로, 실 서비스에 적용하여 테스트 하기에는 적합하지 않다.
출처: http://lefthand.tistory.com/28 [lefthand's note]
[SQL] mysql
command line 기준으로 간략히 정리함.
[로그온]
mysql -u[id] -p [dbname]
[계정생성]
: 많은 항목 중 다음의 컬럼만으로 기본 사용자 생성/등록
$ mysql -u root -p mysql
mysql> INSERT INTO user (Host, User, Password) VALUES ('localhost', 'userid', password('userpwd'));
mysql> INSERT INTO user (Host, User, Password) VALUES ('%', 'userid', password('userpwd'));
mysql> FLUSH PRIVILEGES;
[계정삭제]
mysql> DELETE FROM user WHERE user='userid';
mysql> FLUSH PRIVILEGES;
[데이타베이스 생성]
$ mysql -u root -p mysql
mysql> CREATE DATABASE dbname;
[데이타베이스 목록 조회]
mysql> SHOW DATABASES;
[데이타베이스 삭제]
mysql> DROP DATABASE [IF EXISTS] dbname;
IF EXISTS 는 db 가 없더라도 오류 발생시키지 않는다.
[작업db 변경]
mysql> USE dbname;
[db 접근권한 설정]
(1) 접근권한을 DB 에 직접 UPDATE 하는 방법
mysql> INSERT INTO db (Host, Db, User, Select_priv, Insert_priv, Update_priv, Delete_priv, Create_priv, Drop_priv, Grant_priv, References_priv, Index_priv, Alter_priv, Create_tmp_table_priv, Lock_tables_priv, Create_view_priv, Show_view_priv, Create_routine_priv, Alter_routine_priv, Execute_priv) VALUES ('localhost','dbname','userid','y','y','y','y','y','y','y','y','y','y','y','y','y','y','y','y','y');
mysql> FLUSH PRIVILEGES;
(2) grant 명령 이용 : 생성된 user 가 없는 경우, user 생성까지 수행한다.
mysql> GRANT ALL
-> ON dbname.* TO 'userid'@'host'
-> IDENTIFIED BY 'pwd';
mysql> FLUSH PRIVILEGES;
ex) 로컬호스트에서 userA가 dbA 에 수행항목과 접근 허용
GRANT SELECT, UPDATE, INSERT, DELETE, ALTER, CREATE
ON dbA TO 'userA'@'localhost'
IDENTIFIED BY 'userApwd';
ex2) 모든 서버에서 접근할 수 있도록 허용
GRANT SELECT, UPDATE, INSERT, DELETE, ALTER, CREATE
ON dbA TO 'userA'@'%'
IDENTIFIED BY 'userApwd';
[생성된 계정으로 로긴]
$ mysql -u userid -p [dbname]
[테이블 목록 조회]
mysql> SHOW TABLES;
[테이블 스키마 조회]
mysql> EXPLAIN tablename;
or
mysql> DESCRIBE tablename;
[테이블 생성]
mysql> CREATE TABLE tablename (
-> column_name1 INT UNSIGNED NOT NULL,
-> column_name2 VARCHAR(15) NOT NULL,
-> column_name3 INT );
[테이블 이름 변경]
mysql> RENAME TABLE tablename1 TO tablename2[, tablename3 TO tablename4];
[테이블 삭제]
mysql> DROP TABLE tablename;
[제약 조건 생성]
mysql> CREATE INDEX indexname ON tablename (columnname1[, columname2]);
[로컬 파일 import]
CSV 등 파일에서 import 하여 테이블을 생성한다.
mysql> LOAD DATA LOCAL INFILE 'filepath'
-> INTO TABLE tablename
-> FIELDS TERMINATED BY ','
-> OPTIONALLY ENCLOSED BY '\"'
-> LINES TERMINATED BY '\n' ;
[DB 상태 보기]
mysql> STATUS;
[INSERT]
mysql> INSERT INTO tablename VALUES(value1, value2, ...);
or
mysql> INSERT INTO tablename(column1, column2, ..) VALUES(value1, value2, ...);
[SELECT]
mysql> SELECT column1, column2, .. FROM tablename;
mysql> SELECT column1 AS 'Alias1', column2 AS 'Alias2', .. FROM tablename;
mysql> SELECT * FROM tablename ORDER BY column1 DESC;
mysql> SELECT * FROM tablename WHERE 조건;
[UPDATE]
mysql> UPDATE tablename SET column1=새값 WHERE 조건;
[DELETE]
mysql> DELETE FROM tablename WHERE 조건;
출처: http://lefthand.tistory.com/26 [lefthand's note]
windows application exception
- build 시 pdb 생성
- 유저모드 덤프 설정
(아래의 툴을 이용해서 덤프 출력.)
http://www.microsoft.com/downloads/details.aspx?FamilyID=E089CA41-6A87-40C8-BF69-28AC08570B7E&displaylang=en
:이걸 설치하면 옵션이 몇개 있는데 설정하고 해당 exe를 등록해 놓으면 그 exe가 exception이 나면 덤프가 자동을 떠짐
- windbg이용 덤프분석
windbg에서 !analyze -v 치면 바로 확인됨.
소스 연결해 놓으면 소스까지 다 찾아감
출처: http://lefthand.tistory.com/25 [lefthand's note]