반응형

Checkstyle은 소스 코드가 준수하면 바람직한 많은 스타일 규칙을 제공하고 있다. 다음 표는 Checkstyle이 지원하는 코딩 스타일 규칙 중 기본적으로 탑재된 Sun 코딩 스타일 규칙[1] 중 일부를 보여준다.

범주 설명
Javadoc Comments 패키지, 메소드, 변수에 대한 문서화 스타일 검사
Naming Conventions 표준 명명 규약 검사를 위한 규칙
Imports 불필요하거나 중복된 Import 검사
Size Violations 과도하게 긴 문장, 메소드 혹은 많은 매개변수
Blocks 불필요하거나 필요하지만 생략된 괄호 검사
Coding Problems 하드코딩, 불필요한 표현이나 문장 검사
Class Design 불필요하거나 필요하지만 생략된 Modifier 또는 생성자 검사
Miscellaneous 배열 스타일, 매개변수 스타일 등의 기타 스타일 규칙



추가적으로 Checkstyle은 코딩 스타일을 새롭게 정의하거나 기존의 코딩 스타일을 수정하여 확장할 수 있는 기능도 제공하고 있다. Eclipse의 Windows -> Properties 창의 Checkstyle에서 New 버튼을 클릭하여 새로운 규칙을 추가할 수 있다.

참고로 Checkstyle이 제공하는 스타일 규칙에 대한 설명은 다음에서 확인할 수 있다. http://checkstyle.sourceforge.net/availablechecks.html

 

 

 

코딩 스타일  검사는 소스 코드를 구성하는 클래스/메소드/변수 등의 이름과 문장들의 형태의 일관성을 유지함으로써 소스 코드의 가독성을 높이고 결함의 가능성이 있는 문장 패턴을 검출하여 제거함으로써 소스 코드의 신뢰성을 높이는 것을 목표로 한다.

코딩 스타일 검사에서는 소스 코드를 구성하는 클래스/인터페이스/메소드/필드 등의 명명 방법과 코드의 작성 형태에 대한 규칙을 검사한다. 예를 들어 “한 행에 하나의 선언만을 한다.” 스타일이 있다. 다음은 이 스타일을 준수하지 않는 코드(좌측)와 준수하는 코드(우측)를 보여준다.

비 권장 권장
int age, grade ;
int age ;
int grade ;

 

일관된 코드를 통해서 가독성을 높이기 위해서는 개발자들이 공통적으로 사용하는 코딩 스타일을 정의할 필요가 있다. 코딩 스타일은 Java, C++ 등과 같은 언어에 따라서 별도로 정의가 된다. 다음은 Java 언어와 C++ 언어의 대표적인 코딩 스타일을 보여 준다.

언어 대표적인 코딩 스타일 정의
Java
  • Oracle: Code Conventions for the Java Programming Language[1]
  • Google Android: Code Style Guidelines for Contributors[2]
C++
  • Google C++ Style Guide[3]
  • GCC Coding Conventions[4]

 


[1] http://www.oracle.com/technetwork/java/javase/documentation/codeconvtoc-136057.html
[2] http://source.android.com/source/code-style.html
[3] http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
[4] http://gcc.gnu.org/codingconventions.html

 

 

 

출처 :  http://soft-tnq.com/wordpress/?p=5532

 

반응형
반응형
<tx:annotation-driven />
<aop:config>
<aop:advisor advice-ref="transactionAdvice" pointcut="bean(*Service)" />
</aop:config>

<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="exceptionPut" propagation="REQUIRES_NEW" />
<tx:method name="get*" propagation="REQUIRED" read-only="true" />
<tx:method name="*" />
</tx:attributes>
</tx:advice>

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>

전 장에서 <aop>까지 했으니 이제 <tx> 요소에 대해 설명할 차례네요. <tx>는 스프링 트랜잭션 기술의 집약체입니다. 스프링의 트랜잭션 기술은 전장에서도 말했듯이 어노테이션 적용법과 AOP 적용법 2가지가 있으며 위의 예제는 당연히 AOP 적용법입니다.

먼저 <tx:advice>로 트랜잭션 어드바이스를 하나 만듭니다. 여기에 적용한 트랜잭션을 선택하는데 만약 트랜잭션 빈의 이름이 'transactionManager'이라면 위의 'transaction-manager' 속성은 생략될 수 있습니다. 위의 예제에서는 다만 원리를 설명하기 위해 속성을 넣어둔 것 뿐이므로 현재 'transaction-manager'은 생략이 가능하다 할 수 있겠네요.

그다음 <tx:attributes>의 <tx:method>로 세밀하게 메서드별 속성을 조절해주도록 합시다. 우리는 이 부분에서 어느 메서드에 트랜잭션을 적용할 것인지 선택할 수 있으며 속성에는 다음과 같은 값들이 존재합니다.

name - 메서드명
메서드의 이름이며 와일드 문자(*)를 사용할 수 있습니다. 예로 'get*'은 get으로 시작하는 모든 메서드를 가리키며'*get'은 get으로 끝나는 모든 메서드를 가리킵니다.

timeout - 제한시간 (기본값 : -1)
트랜잭션의 제한시간을 설정합니다. DB가 해당기능을 지원해야 하며 기본값으로는 -1인 제한시간 없음이 설정됩니다.

propagation - 전파옵션 (기본값 : REQUIRED)
REQUIRED : 부모 트랜잭션 내에서 실행하며 부모 트랜잭션이 없을 경우 새로운 트랜잭션을 생성합니다.
REQUIRES_NEW : 부모 트랜잭션을 무시하고 무조건 새로운 트랜잭션이 생성되도록 합니다.
SUPPORT : 부모 트랜잭션 내에서 실행하며 부모 트랜잭션이 없을 경우 nontransactionally로 실행됩니다.
MANDATORY : 부모 트랜잭션 내에서 실행되며 부모 트랜잭션이 없을 경우 예외가 발생됩니다.
NOT_SUPPORT : nontransactionally로 실행하며 부모 트랜잭션 내에서 실행될 경우 일시 정지 됩니다.
NEVER : nontransactionally로 실행되며 부모 트랜잭션이 존재한다면 예외가 발생합니다.
NESTED : 해당 메서드가 부모 트랜잭션에서 진행될 경우 별개로 커밋되거나 롤백될 수 있습니다. 둘러싼 트랜잭션이 없을 경우 REQUIRED와 동일하게 작동합니다.

isolation - 격리수준 (기본값 : DEFAULT)

DEFAULT : DB에서 설정된 기본 격리 수준을 따릅니다.
SERIALIZABLE : 가장 높은 격리수준을 가지며 사용시 성능 저하가 있을 수 있습니다.
READ_UNCOMMITTED : 커밋되지 않은 데이터에 대한 읽기를 허용합니다.
READ_COMMITTED : 커밋된 트랜잭션에 대해 읽기를 허용합니다.
REPEATABLE_READ : 동일한 필드에 대한 다중 접근 시 동일한 결과를 얻을 수 잇는 것을 보장합니다.

read-only - 읽기전용 (기본값 : false)

해당 메서드는 오로지 읽기에만 사용됩니다. INSERT나 UPDATE, DELETE문은 허용되지 않습니다. 만약 쓰기나 삭제가 실행될 경우 에러를 발생시킵니다.

rollback-for - 예외처리 (기본값 :  RuntimeException)

특정 예외가 발생했을 경우에 롤백되도록 설정합니다. 설정하지 않을 경우 오로지 RuntimeException을 상속받은 예외에만 롤백처리를 해줍니다.

no-rollback-for - 예외처리 (기본값 : 없음)

특정 예외가 발생하더라도 롤백되지 않도록 설정합니다.

위의 속성과 값들이 <tx:method>에서 설정할 수 있는 전부입니다. 잘 알아본 다음 자신에게 맞는 속성을 설정한 후에 완성된 <tx:advice>를 <aop:config>에 주입하기만 하면 자동프록시검색기가 알아서 <tx>어드바이스와 pointcut을 해석하여 해당 요청을 대신 처리해 줄 것입니다.

이제 거의 막바지에 왔네요. 다음은 <tx:annotation-driven />에 대한 설명입니다. 이 요소가 설정되있다면 트랜잭션을 어노테이션으로 설정 가능하게 합니다. 설정방법은 트랜잭션을 원하는 메서드에 @Transactional이란 어노테이션을 붙이면 그만이며 <aop>설정은 어노테이션과 전혀 무관합니다. 어노테이션 트랜잭션은 오로지 <tx:annotation-driven /> 요소만을 요구합니다.

@Transactional(isolation=Isolation.DEFAULT, propagation=Propagation.REQUIRES_NEW)

어노테이션으로 트랜잭션으로 설정하는 방법은 직관적이고 알기 쉽지만 수정이 필요할 때에는 코드 자체를 수정해야 한다는 단점이 있습니다. 위의 예시처럼 어노테이션도 <tx:method>와 같이 똑같은 옵션설정이 가능합니다. 설정방법은 이클립스의 자동완성기능(CTRL + F1)으로 알아보시면 편리하니 따로 설명하지는 않겠습니다 :D

일단 어노테이션으로 트랜잭션을 설정할 시 주의할 점은 가장 우선적으로 고려되는 순서가 있다는 것입니다. 만약 인터페이스 - 클래스 - 메서드 모두에 트랜잭션 어노테이션이 설정되있다면 스프링은 메서드 어노테이션을 제일 먼저 고려하고 그 다음이 클래스, 인터페이스 순서으로 적용합니다. 개인적으로는 가급적 어드바이스를 활용해 트랜잭션 경계를 설정하는 게 좋다고 생각하는데 어노테이션 트랜잭션을 남발할 경우 작성된 프레임워크의 잦은 수정이 불가피해지기 때문입니다.

트랜잭션도 상황에 따라 자주 설정이 변경되어줘야 하는데 어노테이션으로 설정을 고정해버리고 매번 수정이 필요할 때마다 소스자체를 바꾸다보면 다른 코드에 영향을 줄 수도 있고 이용하는 사람 입장에서도 상당히 불편할 수 있습니다. 가급적 어드바이스로 트랜잭션 경계를 설정하고 정말 불변하는 트랜잭션에 대해서만 어노테이션을 이용하길 권장합니다.


이제 마지막으로 트랜잭션 매니저 설정을 위한 PlatformTransactionManager을 설명하고 끝마치려 합니다 ^^. 스프링은 다양한 플랫폼과 환경에서도 완벽하게 트랜잭션 클래스들의 DI가 가능 하도록 PlatformTransactionManager 인터페이스를 갖고 있다는 사실을 알고 계신가요?

우리가 구현했던 소스에서는 볼 수 없었지만 분명 <tx:advice>를 구성하는 소스에는 PlatformTransactionManager 인터페이스를 통해 구현 클래스의 주입을 요구하고 있습니다. 현재의 소스는 제가 JDBC/MyBatis를 이용하고 있으므로 위의 예제와 같이 DataSrouceTransactionManager 클래스를 이용해 트랜잭션 매니저를 구현했지만 만약 하이버네트나 JTA같은 다른 플랫폼을 이용할 경우에도 소스에 변경 일절 없이 오로지 트랜잭션 매니저만 변경해주면 간편하게 모든 설정을 끝마칠 수 있습니다.

이렇게 트랜잭션에 대한 모든 설명이 끝났네요. 사실 부족한 부분이 많지만 이정도면 스프링에서 어떻게 트랜잭션을 설정하였고 활용방안에 대한 감을 잡을 수 있다는 생각이 듭니다. 부족한 부분이나 이해가 안가시는 부분은 피드백 주시구요. 다음에 좀 더 좋은 포스트로 찾아올게요 ^^

 

출처 : http://springmvc.egloos.com/499291

 

반응형

'Spring' 카테고리의 다른 글

Spring Transaction #1  (0) 2014.10.01
VO, DTO, DAO  (0) 2013.07.08
domain object에 대한...  (0) 2013.07.08
Spring Java Mail  (0) 2013.07.05
Spring MultipartResolver  (0) 2013.07.02
반응형

스프링만의 독특한 트랜잭션 비법! 1장

springmvc.egloos.com/498979

평소에 "다나까"체로 글을 썼는데 이런 글이 가독성에 참 좋지 않은데다가 쥐뿔도 모르면서 남한테 설교하는 느낌이 너무 나가지고 문체를 "~습니다요"체로 바꾸도록 하겠습니다 ^^;



일전에 썼던 트랜잭션에 대한 원리글을 읽으셨다면 앞으로 우리가 사용할 트랜잭션이 무엇인지 대충 감 잡으셨다고 생각합니다 ^^; 제대로 읽었음에도 잘 이해가 가지 않으시다면 제 글이 부족한 탓이니… 토비의 스프링의 5.2 트랜잭션 서비스 추상화 부분을 정독해보세요. 제 블로그 글보다 더 자세한 디테일한 설명이 담겨져 있답니다.

오늘은 본격적으로 스프링의 트랜잭션 적용법에 대해 이야기 하고자 합니다. 스프링 트랜잭션 적용법은 정말 독특한데다 적용법만 하더라도 애노테이션 적용법AOP적용법 2가지나 존재합니다. 물론 두가지를 한번에 사용하는 것도 가능하구요. 게다가 몇가지 간단한 설정만으로도 메서드 단위까지 세세한 트랜잭션 적용이 가능하니 그야말로 jQuery의 모토처럼 "The Write Less, Do More"의 원칙을 준수하였다고 보면 되겠습니다.

먼저 간단한 원리부터 설명하고자 합니다. 과거 스프링같이 트랜잭션을 위한 프레임워크가 없었던 시절 우리가 트랜잭션을 적용하기 위해선 다음과 같은 원리로 작성해야만 했습니다.

단 2개의 쿼리문을 실행시키기 위해 거의 100줄에 가까운 코드를 작성해야만 합니다. 스프링 트랜잭션과 MyBatis를 이용하면 10줄이나 될까말까한 코드를 말입니다! 게다가 이런식으로 코드를 짜간다면 가독성은 둘째치고 유지보수부터 큰 문제가 생기는데다 중간에 에러라도 한줄 발생한다면 개발자는 처음부터 끝까지 코드를 재검색해야만 합니다.

개발자들이 트래잭션 한번 적용해보겠다고 이렇게까지 코드를 쳐대야 했으니 회사에서 업무효율 상 트랜잭션보단 프로시져를 편들어 주었던 과거 개발환경도 어느 정도 이해는 갑니다. 프로시져는 DB에 로직을 등록하고 java에서는 "call ~procedure~"한줄이면 만사 오케이였으니까요.

그렇다면 이번엔 스프링 트랜잭션으로 확바뀐 트랜잭션 적용법을 알아보겠습니다.

<tx:annotation-driven />

<aop:config>
<aop:advisor pointcut="bean(*Service)" advice-ref="transactionAdvice" />
</aop:config>

<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="exceptionPut" propagation="REQUIRES_NEW" />
<tx:method name="get*" propagation="REQUIRED" read-only="true" />
<tx:method name="*" />
</tx:attributes>
</tx:advice>

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>

위의 예제는 필자의 소스에서 스프링의 트랜잭션 적용한 부분만 도려낸 것입니다. 소스만 봐서 이해가 가지 않는다고 걱정하지 마세요. 스프링은 트랜잭션이란 개념을 완전히 들어엎은 신개념 트랜잭션인데다가 어떻게 이런 설정이 가능했는지 쉽게 감이 오지 않는 기술이니까요.(물론 사용법은 쉽습니다.) 간단히 설명을 하자면 스프링은 트랜잭션 경계범위를 정규표현식과 애노테이션으로 설정하기를 권장하고 있습니다. 물론 반드시 그렇게 해야 한다는 것은 아니지만 굳이 넣지 않아도 될 트랜잭션 선언 코드를 무리하게 자신의 클래스에 꾸역꾸역 넣고 싶은 사람은 아무도 없겠지요.

일단 스프링의 트랜잭션을 이해하기 위해서는 AOP개념과 더불어 몇가지 알아야 하는 용어가 있는데요. 우선적으로 트랜잭션을 이해하기 위해 필요한 것만 뽑자면 다음의 4가지 용어를 알아야 할 것 같습니다.


포인트 컷과 어드바이스

<aop:advisor pointcut="bean(*Service)" advice-ref="transactionAdvice" />


먼저 스프링 트랜잭션의 가장 기초가 되는 포인트 컷과 어드바이스에 대해 알아봅시다. 포인트컷은 자동 프록시 생성기가 검색할 클래스(또는 메서드)를 선별하는 역할을 담당합니다. 위의 예제 중 pointcut = "bean(*Service)"처럼 설정한다면 빈 중에서 Service로 끝나는 모든 빈을 선택하게 됩니다.

포인트컷은 학습테스트나 특별한 기능을 위해서라면 org.springframework.aop.Pointcut 인터페이스를 구현하여 따로 클래스로 만들 수도 있지만 보통은 위의 예제처럼 간편하게 <aop:advisor> 내에 위치시키는 방법이 일반적입니다. 다만 하나 이상의 포인트컷을 입력하고 싶다면 아래 이미지와 같이 구성할 수도 있습니다.

AOP에서 포인트 컷을 설정하기 위한 표현식(expression)은 매우 다양하므로 그 방법은 차후에 다른 포스트를 통해 올리도록 하겠습니다. 좀 더 유익하게 트랜잭션 기술을 이용하기 위해서라면 표현식은 필수적으로 연마해야할 스킬입니다.

다음으로 우리가 알아볼 것은 바로 어드바이스입니다. 어드바이스는 포인트컷으로 선택한 빈에 적용될 부가기능을 뜻합니다. AOP는 트랜잭션만을 위한 기술이 아니기 때문에 필요하다면 어드바이스를 통해 포인트컷으로 선별될 빈(또는 클래스, 메서드)의 적용 기술을 자유롭게 변경할 수 있습니다. 물론 여기서 우리가 적용할 부가기능은 바로 트랜잭션입니다.

이런 어드바이스는 org.aopalliance.intercept.MethodInterceptor를 구현하여 만들어집니다. 사실 좀 기나긴 이야기가 되겠지만 이런 어드바이스의 개념을 이해하기 위해서는 프록시와 다이나믹 프록시, 그리고 팩토리빈으로 이어지는 프록시의 발전사를 어느 정도 이해해야만 합니다. 특히 다이나믹 프록시는 그 개념이 상당히 복잡하여 몇줄로 설명할 수 없는 패턴이지만 그래도 나름 간략하게 설명해본다면 기존의 프록시 패턴에서 발전하여 코드의 재사용성을 높인 새로운 프록시 기술이라 할 수 있습니다. (팩토리빈은 그런 다이나믹 프록시를 한단계 더 끌어올린 기술입니다.)

생각해보니 프록시 패턴을 모르시는 분을 위해 프록시 패턴에 대해서도 설명이 필요하겠군요. 프록시 패턴이란 일종의 래퍼개념입니다. 예를 들어 인터넷을 자주 이용해본 독자라면 프록시 서버라는 말을 종종 들어보셨을 겁니다. 이 프록시 서버는 기존의 핵심기능이 수행되는 순간 그 기능을 가로채어 앞뒤로 미리 설정된 프록시 기능을 수행해주는 역할을 합니다. 이 기능은 접속 시에 개인정보를 요구하는 것이 될 수도 있고 접속 시 필요한 서버 정보가 덧붙여진 것일 수도 있습니다.

우리가 이런 프록시 서버처럼 기존 기능을 가로채는 프록시 패턴을 완벽하게 구현하기 위해서는 프록시 클래스에서 본래의 클래스를 주입받고 또 주입받은 클래스의 모든 기능을 전부 대신 작동하게끔 대체 메서드를 작성해야 되는데 이게 여간 쉬운 작업이 아닙니다!

프록시 패턴의 예제

위의 예제는 간단하게 AutoWriter라는 클래스에 프록시 패턴을 적용한 Proxy란 클래스를 만든 예제인데, 이것만으로 자바의 프록시 패턴이 무엇이냐 정의해 본다면 새로운 프록시 클래스의 기존의 클래스의 기능을 모두 재정의한 대체 클래스라 정의할 수 있겠군요. 근데 이런 프록시 패턴에는 한가지 중대한 문제점 존재합니다.

일단 한번 상상해봅시다. 지금은 AutoWriter란 클래스가 단 2개의 메서드밖에 없지만 만약 메서드가 한 10개에서 20개 정도로 늘어났다고 말입니다. 게다가 클라이언트가 취향이 매우 까다로와 기존의 메서드에서 종류별, 분야별, 느낌별, 감성별로 기능을 나눠달라고 생때를 부린 통에 어쩔 수 없이 프록시 클래스를 한 20개 정도나 만들어야 된다면 작업 분량이 얼마나 될까요?

벌써부터 최소 200~400개의 메서드를 일일이 타이핑 해줘야 한다는 계산이 나오는군요. 세상에… 정말로 이렇게 클래스를 만들어야 한다면 프록시 클래스만 만들면서 한 일주일은 보내야 할판입니다. 근데 다행히도 자바에는 이런 문제를 해결할 수 있는 방법을 내장해 두었습니다. 그것은 바로 다이나믹 프록시입니다.


위의 이미지는 프록시의 핵심개념이므로 잘 이해하셔야 됩니다. 프록시 패턴의 핵심원리는 기존의 기능의 앞, 뒤로 프록시 기능을수행만 하면 된다는 것입니다. 그러므로 기존 기능만 알아서 반복동작한다면 프로그래머는 앞뒤로 덧붙일 기능만 작성하면 됩니다. 다이나믹 프록시는 이런 원리에 입각하여 기존의 메서드를 전부 재작성할 필요 없이 하나의 메서드에 덧붙일 새로운 프록시 기능만 완성시키면 자동으로 모든 메서드에 동일한 프록시 기능을 생성시켜줍니다.

이런 원리의 다이나믹 프록시를 업무에 적용한다면 기존의 400개의 메서드는 20개의 메서드로 분량이 획기적으로 줄어들게 됩니다. 그렇다면 어드바이스와 지금 설명하고 잇는 다이나믹 프록시와는 도대체 무슨 상관관계가 있는 것일까요? 그것은 어드바이스는 자체가 바로 이 다이나믹 프록시이기 때문입니다. (정확히 다이나믹 프록시의 구현부라고 합니다.)

MethodInterceptor 인터페이스는 스프링의 어드바이스를 작성하기 위해 구현해야 할 (스프링에서 사용되는) 다이나믹 프록시 인터페이스입니다. 우리가 MethodInterceptor를 구현하게 되면 반드시 invoke란 메서드를 구현해야 합니다. 바로 이 invoke메서드가 대체할 클래스의 모든 메서드를 실행하게 됩니다. 그러므로 우리는 이 invoke메서드에 기존의 기능에 앞뒤로 덧붙이기만 하면 다이나믹 프록시가 완성됩니다. 그리고 이것을 포인트컷과 함께 어드바이저에 넘겨주면 끝이죠.

드리고 싶은 말은 다이나믹 프록시 기술은 굳이 트랜잭션 뿐만 아니라 여러분의 코드 전반에 걸쳐 사용될 수 있는 기막힌 고급기술입니다. 어드바이스는 한번 배워두면 두고두고 써먹을 소중한 기술이므로 자세한 어드바이스 작성법을 배우기 위해서 토비의 스프링 책의 ProxyFactoryBean 작성 부분을 유심히 읽어보시기 바랍니다. 그리고 자기 나름대로의 어드바이스를 한번 만들어 보세요.


어드바이저

이제 포인트컷과 어드바이스에 대한 이해가 끝나셨다면 어드바이저를 이해하실 차례입니다. 어드바이저는 이렇게 모인 어드바이스와 포인트컷의 정보를 참조하는 기능을 수행합니다. AOP에서 제공하는 기본 어드바이저인 org.springframework.aop.support.DefaultPointcutAdvisor를 이용하신다면 특별히 새로운 어드바이저 클래스를 만들 일은 없습니다. 그래도 자신만의 어드바이저 클래스를 구현하고 싶으시다면 어드바이저는 org.springframework.aop.Advisor 인터페이스를 구현해서 만들어야 한다는 사실을 기억하세요.

자동프록시생성기

자동프록시생성기는 기본적으로 org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator 클래스를 뜻합니다. 이 클래스가 빈으로 등록되어 있다면 자동으로 Advisor 인터페이스를 구현한 빈이 컨텍스트에 등록되었는지를 확인해주고 해당 어드바이저들에 정의되있는 포인트컷과 어드바이스를 해석하여 해당 요청이 왔을 때 자동으로 이 요청을 가로채어 프록시를 생성해줍니다.

그야말로 스프링 기술의 정점이라고 할 수 있는데요. 사용법은 컨텍스트에 해당 빈을 생성해주기만 하는 것으로 끝이 납니다.

<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />

자동프록시생성기는 어디에 참조되지도 않고 무엇을 참조하지도 않으므로 id도 필요없습니다. 등록된 순간 마치 인공지능처럼 알아서 모든 요청을 처리해주는 기특한 녀석입니다. 근데 여기까지 자동프록시생성기에 대한 이야기를 읽다보면 조금 이상한 점이 눈에 띕니다. 뭐냐하면 상단에 필자의 트랜잭션 적용 예제에선 자동프록시생성기를 등록하는 부분이 어디에도 보이지 않으니 말입니다. 제가 빼먹거나 일부러 넣지 않은 것은 아닙니다. 게다가 위의 예제만 등록하더라도 트랜잭션의 기능이 훌륭하게 동작하니 말입니다. 그렇다면 도대체 이 자동프록시생성기는 어떻게 된걸까요?

먼저 우리는 스프링에서 제공하는 AOP기술에 대해 바로 알아야 합니다. 필자가 잘못 이해하지 않았다면 스프링의 AOP기술은 바로 자동프록시생성기 그 자체입니다. <aop> 요소로 이용할 수 있는 기능이 무엇이 있나 한번 살펴보죠. <aop:config />, <aop:aspectj-autoproxy />, <aop:scoped-proxy />가 전부입니다. 즉 AOP로 우리가 할 수 있는 것은 자동프록시생성기의 생성주기를 설정하고 자동프록시생성기를 설정하고 또 어드바이저를 등록하는 것이 전부입니다. 이렇게 본다면 스프링 AOP가 자동프록시생성기 그 자체라는 말도 그렇게 허황된 말은 아닙니다. 우리가 AOP를 이용한다는 것은 다이나믹 프록시 기술을 이용한다는 것이고 스프링 원칙에 따라 모든 설정의 기본값으로 적용된 자동프록시생성기가 컨텍스트에 등록되게 됩니다.

그러므로 스프링은 자동프록시생성기를 <aop:config> 요소를 선언함과 동시에 자동으로 등록되도록 하였습니다. 다만 등록되는 자동프록시생성기는 DefaultAdvisorAutoProxyCreator 클래스가 아닌 AspectJAwareAdvisorAutoProxyCreator 클래스이긴 하지만 여하튼 어느 자동프록기생성기를 등록하건 우리는 딱 한가지 약속을 보장 받을 수 있습니다. <aop:config>에서 등록된 어드바이저들은 모두 자동프록시생성기를 통해 해당 포인트컷으로 클래스를 인터셉터하고 어드바이스에 등록된 기능을 수행한다는 보장 말입니다.

스크롤이 길어지는 관계로 다음 이야기는 2장에서 계속 하도록 하겠습니다 ^^;
반응형

'Spring' 카테고리의 다른 글

Spring Transaction #2  (0) 2014.10.01
VO, DTO, DAO  (0) 2013.07.08
domain object에 대한...  (0) 2013.07.08
Spring Java Mail  (0) 2013.07.05
Spring MultipartResolver  (0) 2013.07.02
반응형

 

EJB에 대한 개념을 정리해 보도록 하겠습니다. 음.. EJB라고 하면 엔터프라이즈 자바 빈(Enterprise Java Bean)이라고 하는 건 다들 아시죠^^ 썰렁했나? 그런데 이말가지고는 EJB의 뜻을 해석 하기는 어려우실 건니까 분산환경, RMI등을 이해 한 후 EJB에 대해 알아 보기로 하겠습니다.

우선 EJB를 보시기 전에 자바 RMI라고 하는것에 대해 알아 보자구요, Java RMI는 Remote Method Invocation의 머리말을 딴 말인데 JDK1.1부터 자바에 내장된 기술입니다. Java 환경에서 Computer 간 또는 Program 간에 통신(객체를 주고 받을 수 있습니다)을 할 수 있는 기능을 제공합니다. 자바에 내장 되었다는 것은 CORBA, DCOM, EJB등은 통신을 대신 해주는 미들웨어(Middleware)가 필요한데(EJB를 사용하기 위해서는 이 사이트에서 강좌가 진행 중인 웹 로직, 웹 스피어등의 미들웨어가 필요하다는 겁니다.), RMI는 이미 JVM에서 지원을 한다는 이야기죠… 제 생각엔 분산 시스템 환경을 구축하는데 간단한 것이라면 RMI를 추천 합니다. 그리고 미들웨어라는 말이 자주 보이는데 이것은 분산 환경에서 애플리케이션들이 연결되어 서로 데이터를 교환할 수 있게 해 주는 Software정도로 보시면 되겠습니다.

객체 지향의 개념에서 프로그램이 객체들 간의 메세지 전송으로 실행 된다는 이야기를 많이 보셨을 겁니다. 그런데 만약 그 객체들이 서로 다른 컴퓨터에 존재한다면 어떨까요? 과거 분산 시스템은 서로 다른 프로그램들이 다른 컴퓨터에 존재하고 실행되는 것이었는데 최근의 객체 지향에서는 각 객체가 분산되어 존재하는 개념인 것입니다. 그래서 서로 통신을 하는데 다른 컴퓨터에 있는 객체의 메소드를 호출 한다든지 또는 객체들도 던졌다 받았다 한다는 것이 RMI 입니다.

분산컴퓨팅, 분산객체에 대한 개념에 대해 정리하면 아래와 같습니다. 물론 Java Network 강좌에 나와 있는 내용 입니다.

분산 컴퓨팅 이란? 네트워크에서 서로 다른 시스템 간에 응용 프로그램을 분산해서 처리하는 환경을 말합니다. 즉 하나의 컴퓨터에 존재하는 Application이나 프로세스에서 스스로 처리하거나 수행하기 어려운 작업을 다중 프로세서나 컴퓨터에 분산 시키는 것입니다. 분산 컴퓨팅을 적용한 Application을 Distributed Application 이라고 합니다.

분산 객체 (Distributed Object) 란? 분산 컴퓨팅 기술이 객체 지향과 접목되어 하나의 프로세서나 컴퓨터에서 실행되는 객체가 다른 프로세서나 컴퓨터에서 객체와 통신이 가능 하도록 하는 기술이 분산 객체 기술이며 분산 객체란 자신이 존재하는 런타임 환경과는 다른 런타임에 있는 객체와 통신이 가능한 객체 입니다.

이제 EJB로 돌아와서 개념을 정리해 보죠… EJB는 대규모 분산 객체 시스템을 구축하기 위한 기술 또는 자바로 서버 측 비즈니스 로직을 작성하기 위한 Enterprise 환경에서의 자바 표준이라고 보시면 됩니다. 흔히 프리젠테이션 로직이라고 하는 것이 화면에 보여지게 되는 정보의 타입, 포맷을 자동으로 처리하는 반면 비즈니스 로직은 급여계산 한다든지 하는 보이지 않는 어떤 처리를 하는 겁니다. 만약 EJB를 사용하기 위해 웹로직 서버를 이용한다고 하면 프로그램 개발자는 웹로직 서버의 컨테이너를 이용하여 작업을 하게 되는데 이는 트랜잭션의 지원, 보안, 동시 접근 처리 등 비즈니스 로직을 처리하는데 있어 필요한 모든 것을 제공 한다고 보면 됩니다. EJB는 엔티티빈, 메시지 드리븐 빈, 상태유지 세션 빈, 비상태유지 세션 빈등 4가지의 타입이 있으며 아마도 오라클자바에 오시는 여러 분들은 수준이 높아 공부하시는데 크게 어렵지 않으리라 생각 됩니다. ^^ EJB는 명세, 스펙만 잘아시면 쉽게 공부 할 수 있습니다.

EJB에 대한 이해를 위해서는 앞서 설명 한 분산 환경, 분산 객체, RMI등을 잘 알고 있어야 합니다. 그래서 RMI의 기초가 부분에 대해 부족하시다고 생각이 드는 분은 Java Network의 RMI강좌중 HelloWorld를 따라해 보시고 오시기를 부탁 드리구요, JSP, Servlet등도 공부를 하시기 바랍니다.

EJB기술을 이용하면 다른 곳에 떨어진(원격의) EJB서버 메모리에 떠 있는 클래스를 참조할 수 있습니다. 다시 말씀 드리면 그 클래스의 메소드를 호출 할 수 있다는 이야기 입니다. 즉 EJB도 내부적으로 컴포넌트의 통신을 위해 RMI를 사용 한다는 겁니다. 그리고 분산 환경이라고 무조건 EJB를 쓰시면 큰일 납니다. 미들웨어 구입을 위한 비용은 둘째 치더라도 EJB는 추가적인 overhead가 있으므로 성능 향상을 위한 EJB 보다는 안정성, 재사용 가능한 시스템, 프리젠테이션 영역과 비즈니스 로직의 분리, 신뢰성 있는 N-Tier 환경, 분산 환경이 꼭 필요한가 등을 고려하여 사용 하는 것이 바람 직 합니다. EJB를 사용하기 위해서는 전용 서버(미들웨어)를 사용해야 하는데 SUN에서 제공하는 J2EE서버의 경우 거의 실무에서는 쓰이지 않으며 주로 웹로직, 웹스피어 등을 이용하셔서 개발을 하게 됩니다.

 

 

 

정말 가볍게 잘 정립이 된 것 같습니다. 짱

 

출처 : http://pokey.tistory.com/7

 

반응형
반응형

파일 다운로드 기능 구현시에 

파일명에....브라우저별로 한글파일 및 기호 포함시 깨지는 현상에 대해 해결하기 위해 아래와 같은 내용을 검색하였다.

ㅜㅜ 원작자에게는 죄송하게도... 출처 주소를 기억하지 못해 출처를 표기 못해 너무나 죄송하다.


솔직히 브라우저별로 원인은 정확히 모르겠으나, 해당 메소드 적용시에 4가지 브라우저에서 파일명 깨짐현상이 해결됨을 테스트를 통해 확인하였다.


원작자에게 감사드립니다. 꾸벅!



... 코드는 다음과 같은 방식으로 구현되어야 한다.


// 빈 간, 특수문자, 한글에 대한 테스트

String filename = "바+보 는=바보.-똥개.txt";

String disposition = getDisposition(filename, "UTF-8", getBrowser(request););

char[] content = 적당히......;

 

response.addHeader("Content-disposition", disposition);

 

// 2009. 2. 19 추가

if ("Opera".equals(getBrowser(request))){

    response.setContentType("application/octet-stream;charset=UTF-8");

}


Writer out = response.getWriter();
out.write(content); // <-- 자기 방식으로 넣으세요.. 대충 쓴 거니..
out.flush();



... 위의 코드에서 호출하는 메소드들이다.


 

            private String getBrowser(HttpServletRequest request) {
                String header = request.getHeader("User-Agent");
                if (header.indexOf("MSIE") > -1) {
                    return "MSIE";
                } else if (header.indexOf("Chrome") > -1) {
                    return "Chrome";
                } else if (header.indexOf("Opera") > -1) {
                    return "Opera";
                }
                return "Firefox";
            }

            private String getDisposition(String filename, String browser)

                                                                            throws Exception {
                String dispositionPrefix = "attachment;filename=";
                String encodedFilename = null;
                if (browser.equals("MSIE")) {
                    encodedFilename = URLEncoder.encode(filename, "UTF-8")
                            .replaceAll("\\+", "%20");
                } else if (browser.equals("Firefox")) {
                    encodedFilename =

                 "\"" + new String(filename.getBytes("UTF-8"), "8859_1") + "\"";
                } else if (browser.equals("Opera")) {
                    encodedFilename =

                 "\"" + new String(filename.getBytes("UTF-8"), "8859_1") + "\"";
                } else if (browser.equals("Chrome")) {
                    StringBuffer sb = new StringBuffer();
                    for (int i = 0; i < filename.length(); i++) {
                        char c = filename.charAt(i);
                        if (c > '~') {
                            sb.append(URLEncoder.encode("" + c, "UTF-8"));
                        } else {
                            sb.append(c);
                        }
                    }
                    encodedFilename = sb.toString();
                } else {
                    throw new RuntimeException("Not supported browser");
                }

                return dispositionPrefix + encodedFilename;
            }

간단히 설명하자면,

1. MSIE는 URLEncoder.encode 를 이용해 UTF-8로 인코드해 주기만 하면 된다.

    (아, 공백 문제는 해결해야 함)

    보통 new String(filename.getBytes("MS949"), "8859_1")  를 이용하는데,

    이건 철저하게 국내용이다. 한글 Windows에서 실행한 IE/FF 라면 보통 이게 먹히겠지만

    외국 로케일을 적용한 경우에는 여지없이 파일명이 깨지므로

    가능하다면 어떤 경우에든 먹히는 해법을 시도하는 것이 좋다.

    이게 의심된다면 자신이 만든 어플리케이션을 유닉스에서 LANG 환경변수를 바꿔가면서

    시도해 보자.

    (혹은 Windows라면 언어 설정을 일본어나 다른 언어로 바꾸고 시도해 보자 - 09.01.13 추가)

    (이에 대한 부가설명이 http://blog.naver.com/anabaral/130042610256 에 있다 - 09.02.15 추가)


2. Firefox는 URLEncoder로 인코드한 문자열을 받아들이지 못한다.

    대신 UTF-8 혹은 브라우저가 실행되는 인코딩으로 인코드된 바이너리는 받아들이므로

    일반적으로 통용되는 방식을 사용한다.

    new String(filename.getBytes("UTF-8"), "8859_1") 

    보통은 IE에서와 마찬가지로 위에 MS949를 쓰지만, 고맙게도(?) Firefox는

    위의 인코딩을 UTF-8로만 설정해도 알아서 디코드 해 준다.

    아마도 '브라우저 인코딩' 혹은 '기본 인코딩'으로 시도하고 인식이 안되면 UTF-8을 시도하는 듯.

    다만 공백이 있으면 공백 뒤가 무시되어 잘리므로 앞뒤로 따옴표 " " 를 적용해야 한다.


3. Opera는 상당히 독특한데, Opera는 브라우저 인코딩에 맞추어 파일명을 디코드해 저장한다.

    게다가 URLEncoder 로 인코드한 내용도 안 먹힌다.

    그래서 이 경우는 정답이 없다.

    다만 사용자가 별다른 설정을 하지 않는다면 브라우저 인코딩은 그 전까지 접했던 페이지의

    인코딩을 따라가므로 우리가 일관된 인코딩 정책을 가져가고 그에 맞춰 세팅해 주면 된다.

    위의 예제에서는 그 표준이 UTF-8 이었다.

    최근에(2009.2.19)에 테스트한 바로는 Opera는 다운로드 당시의 ContentType 헤더에 정해준

    charset에 민감하다. 그래서 Content-Type 의 charset과 문자열 인코딩의 charset을 일치

    시켜주면 다운로드에 문제가 없다.

    (그래서 다른 브라우저에서의 UTF-8과는 의미가 다르다)


4. 구글 Chrome도 써보았는데, 이건 URLEncoder 인코드 문자열을 받아들이지만 뭔가 부족하다.

    몇몇 글자들(+, = 등)이 깨지기 때문이다.

    그래서 ASCII 문자(0x00 ~ 0x7e)로 간주되는 부분들은 encode하지 않는 방향으로 진행한다.


5. Safari는 지금까지는 답이 없다..

   무조건 latin1(8859_1)으로 인식하니..


이 예제의 테스트는

Internet Explorer 6,

Internet Explorer 7,

Firefox 2.0,

Firefox 3.0,

Opera 9.62,

Chrome 1.0

( 실패했지만 Safari 3.2.1)

에서 진행했다.


위의 테스트로 빈 칸, 특수문자, 한글에 대한 테스트가 가능했다.

테스트에 협조해 주신 liquidbird 님께 심심한 감사를 표한다.

반응형

'Java기초' 카테고리의 다른 글

jvm 메모리  (0) 2015.12.10
단위 테스트 활용 방법: JUnit 참조 가이드  (0) 2014.11.25
replace replaceAll 차이  (0) 2014.08.01
java stack trace  (0) 2014.05.09
JVM 메모리  (0) 2014.04.30
반응형

두 메소드는 jdk 버젼에 따라 다른 API가 제공되었다.

 

1.4

replace는  replace(char, char)

replaceAll 은 replaceAll(String, String)

 

1.5

replace는 replace(char, char)   ------> 1.4와 동일

replace는 replace(CharSequence, CharSequence)   ------>추가된 api (replaceAll 과 같은 기능인 셈?)

 

replaceAll는 replaceAll(String regex, String replacement) 

 

 

정리해보면

String 값에 대해서 replacement 하는 건, (1.5이후) replace와 replaceAll 모두 가능

그러나, regex(정규식)에 대해 replacement 는 replaceAll 만 가능하다

 

 

반응형

'Java기초' 카테고리의 다른 글

단위 테스트 활용 방법: JUnit 참조 가이드  (0) 2014.11.25
Browser별 file name깨짐현상  (0) 2014.08.13
java stack trace  (0) 2014.05.09
JVM 메모리  (0) 2014.04.30
정규식 특수문자  (0) 2013.07.15
반응형

자바에서 사용되는 Stack Trace를 알아보자
하나의 프로그램을 수행하는 동안 스레드는 다양한 메서드를 돌아다니게 된다.
메서드가 호출되고 종료되면, 메서드를 호출하는 곳으로 다시 돌아가게 된다.
이렇게 호출된 곳으로 다시 돌아가기 위해서는 Stack에 메서드가 호출된 포인트를 기록해야,
그 기록을 따라서 다시 돌아갈 수 있게 된다.
프로그램 실행 중 기록되는 특정 포인트들을 쌓아놓고 활용하는 것이 Stack Trace가 되겠다.
디버깅을 수행할 경우에 유용하게 활용될 수 있다.

프로그램이 수행될 경우, 여러 클래스를 돌아다니면서 작업을 하게 될 수 있다.
이 때, 버그가 발생하면 수많은 메서드 호출을 디버깅과정는 과정을 거쳐야 한다.
버그가 발생되는 곳으로 예상 되는 곳에서 Stack Trace를 하면 어디에서 예상 지역을 호출하는지 알 수 있다.

JAVA Stack Trace 방법
Thread를 이용하여 현재 Thread를 얻어오고, 얻어온 Thread로부터 Stack Trace를 가져온다.
Thread th = Thread.currentThread();
StackTraceElement 배열을 이용하면 받을 수 있게 된다.
StackTraceElement[] lists = th.getStackTrace();
StackTraceElement의 메서드를 이용하여 원하는 내용을 출력하면 된다.
예제에서는 getClassName()과 getMethodName()을 이용한다.

예제를 보자.
public class StackTraceElementTest {
    public void test1(){
        test2();
    }
 
    public void test2(){
        test3();
    }

    public void test3(){
        test4();
    }
 
    public void test4(){
        Thread th = Thread.currentThread();
        StackTraceElement[] lists = th.getStackTrace();
        for(StackTraceElement list : lists){
            System.out.println(list);
            System.out.println(list.getClassName() + " : " + list.getMethodName());
        }
    }
 
    public static void main(String[] args){
        StackTraceElementTest test = new StackTraceElementTest();
        test.test1();
    }
}


위의 예제는 main - test1 - test2- test3- test4를 차례로 호출하고 있다.
test4에서 Stack Trace를 수행하면 다음과 같은 결과가 출력된다.

java.lang.Thread : getStackTrace
JavaStudy.StackTraceElementTest : test4
JavaStudy.StackTraceElementTest : test3
JavaStudy.StackTraceElementTest : test2
JavaStudy.StackTraceElementTest : test1
JavaStudy.StackTraceElementTest : main


getStackTrace를 사용한 지점부터 역순으로 출력을 하게 되므로, main - test1 - test2- test3- test4의 순서로 호출됨을 알 수 있다.


출처 : http://okjkillo.tistory.com/entry/JAVA-Stack-Trace

반응형

'Java기초' 카테고리의 다른 글

Browser별 file name깨짐현상  (0) 2014.08.13
replace replaceAll 차이  (0) 2014.08.01
JVM 메모리  (0) 2014.04.30
정규식 특수문자  (0) 2013.07.15
추상클래스 인터페이스 차이2  (0) 2013.07.11
반응형

1. 메모리

 

프로그램을 실행하기 위한 데이터 및 명령어를 저장하는 공간

 

※ 메모리구조를 공부하는 이유
- 같은 기능의 프로그램이더라도 메모리 관리에 따라 성능이 좌우됨.
- 메모리 관리가 되지 않은 경우 속도저하 현상이나 튕김 현상 등이 일어날 수 있음.
- 한정된 메모리를 효율적으로 사용하여 최고의 성능을 내기 위함.

 

2. 자바 프로그램의 실행구조

 

프로그램이 실행되기 위해서는 windows나 linux같은 운영체제(OS)가 제어하고 있는 시스템의 리소스의 일부인 메모리(RAM : 주기억장치)를 제어할수 있어야 하는데, java이전의 c같은 대부분의 언어로 만들어진 프로그램은 이러한 이유때문에 OS에 종속도어 실행되게 되어 있었다.   

 

java프로그램은 JVM(Java Virtual Machine : 자바가상머신)이라는 프로그램만 있으면 실행이 가능한데, JVM이 OS에게서 메모리 사용권한을 할당받고 JVM이 자바프로그램을 호출하여 실행하게 된다. OS한태서는 독립되었지만 JVM이라는 프로그램에 종속적이게 된다. (JVM을 실행시키고 다시 JVM이 프로그램을 실행시키는 방식이다 보니 OS에 직접 제어받는 방식보다는  속도면에서는 느리다는 단점을 가진다)

 

 

 

 

* JVM이란?

- Java Virtual Machine
- JAVA와 OS 사이에서 중계자 역할
- JAVA가 OS에 구애받지 않고 재사용을 가능하게 해 줌
- 메모리 관리 기능(Garbage Collection)

 

3. 자바프로그램 실행 과정과 JVM메모리 구조

 

프로그램이 실행되면, JVM은 OS으로부터 이 프로그램이 필요로 하는 메모리를 할당받고, JVM은 이 메모리를 용도에 따라 여러 영역으로 나누어 관리한다.

 

 

- JAVA Source : 사용자가 작성한 JAVA 코드
- JAVA Compiler : JAVA 코드를 Byte Code로 변환시켜주는 기능
- Class Loader : Class파일을 메모리(Runtime Data Area)에 적재하는 기능
- Execution Engine : Byte Code를 실행 가능하게 해석해주는 기능
- Runtime Data Area : 프로그램을 수행하기 위해 OS에서 할당 받은 메모리 공간

 

4. Runtime Data Area


① Class Area

 

 

 

- Method Area, Code Area, Static Area 로 불리어짐

i) Field Information : 멤버변수의 이름, 데이터 타입, 접근 제어자에 대한 정보

ii) Method Information : 메서드의 이름, 리턴타입, 매개변수, 접근제어자에 대한 정보

iii) Type Information : - Type의 속성이 Class인지 Interface인지의 여부 저장
- Type의 전체이름(패키지명+클래스명)
- Type의 Super Class의 전체이름
(단, Type이 Interface이거나 Object Class인 경우 제외)
- 접근 제어자 및 연관된 interface의 전체 리스트 저장

iv) 상수 풀(Constant Pool)
- Type에서 사용된 상수를 저장하는 곳(중복이 있을 시 기존의 상수 사용)
- 문자 상수, 타입, 필드, Method의 symbolic reference(객체 이름으로 참조하는 것)도 상수 풀에 저장

v) Class Variable
- Static 변수라고도 불림
- 모든 객체가 공유 할 수 있고, 객체 생성 없이 접근 가능

vi) Class 사용 이전에 메모리 할당
- final class 변수의 경우(상수로 치환되어) 상수 풀에 값 복사

 

② Stack Area

 

 

 

- Last In First Out (LIFO)
- 메서드 호출 시마다 각각의 스택프레임(그 메서드만을 위한 공간)이 생성
- 메서드 안에서 사용되어지는 값들 저장, 호출된 메서드의 매개변수, 지역변수, 리턴 값 및 연산 시 일어나는 값들을 임시로 저장
- 메서드 수행이 끝나면 프레임별로 삭제

 

③ Heap Area

 


 

- new 연산자로 생성된 객체와 배열을 저장하는 공간
- 클래스 영역에 로드된 클래스만 생성가능
- Garbage Collector를 통해 메모리 반환

i) Permanent Generation
- 생성된 객체들의 정보의 주소 값이 저장된 공간

ii) New Area
- Eden : 객체들이 최초로 생성되는 공간
- Survivor : Eden에서 참조되는 객체들이 저장되는 공간

iii) Old Area : New Area에서 일정시간이상 참조되고 있는 객체들이 저장되는 공간

 

④ Native method stack area


- 자바 외의 다른 언어에서 제공되는 메서드들이 저장되는 공간

 

⑤ PC Register


- Thread가 생성 될 때마다 생성되는 공간
- Thread가 어떤 부분을 어떤 명령으로 실행할 지에 대한 기록
- 현재 실행되는 부분의 명령과 주소를 저장

 

5. Garbage Collection


- 참조되지 않은 객체들을 탐색 후 삭제
- 삭제된 객체의 메모리를 반환
- Heap 메모리의 재사용

 

① Minor Garbage Collection

 

i) New 영역에서 일어나는 Garbage Collection
ii) Eden영역에 객체가 가득 차게 되면 첫 번째 Garbage Collection 발생
iii) Survivor1 영역에 값 복사
iv) Survivor1 영역을 제외한 나머지 영역의 객체들을 삭제
v) Eden영역과 Survivor1영역의 메모리가 기준치 이상일 경우, Eden 영역에 생성된
객체와 Survivor1영역에 있는 객체 중 참조되고 있는 객체가 있는지 검사
vi) 참조되고 있는 객체를 Survivor2 영역에 복사
vii) Surviver2 영역을 제외한 영역의 객체들을 삭제
viii) 일정시간이상 참조되고 있는 객체들을 Old영역으로 이동
ix) 반복

 

② Major Garbage Collection (Full Garbage Collection)

 

i) Old영역에 있는 모든 객체들을 검사
ii) 참조되지 않은 객체들을 한꺼번에 삭제
iii) Minor Garbage Collection에 비해 시간이 오래 걸리고 실행 중 프로세스가 정지


출처 : http://huelet.tistory.com/entry/JVM-%EB%A9%94%EB%AA%A8%EB%A6%AC%EA%B5%AC%EC%A1%B0


반응형

'Java기초' 카테고리의 다른 글

replace replaceAll 차이  (0) 2014.08.01
java stack trace  (0) 2014.05.09
정규식 특수문자  (0) 2013.07.15
추상클래스 인터페이스 차이2  (0) 2013.07.11
인터페이스 추상클래스  (0) 2013.07.11
반응형

XHTML이 어떤 마크업 언어이고, 어떤 한계를 가지고 있는지를 앞선 글에서 알아봤습니다. 그렇다면 HTML 대신XHTML을 사용하는 것은 과연 옳은 선택일까요? 이 주제에 관해서 포스팅하게 된 동기가 되었던 Tommy Olsson의 글에서는 이 문제에 대해서 부정적인 입장을 취하고 있습니다. XHTML이 실제로는 HTML과 거의 동일하게 취급되므로 구태여 XHTML을 사용할 필요가 없다는 주장이지요.

하지만 XHTML을 이용한 홈페이지와 블로그를 만들고 운영하는 제 생각은 그와는 다릅니다. XHTML이 HTML 대신 사용되는 것을 굳이 말릴 필요는 없다고 생각하거든요.

물론 이 문제에는 정답이 없습니다. 각자가 생각하고 판단해야 할 문제니까요. 그 판단을 돕기 위해서 각각의 주장에 대해서 자세히 설명하려는 것이 이 글의 목적입니다.

그리고 이 글은 XHTML 1.0과 HTML 4.01 규격을 비교하는데 중점을 두겠습니다. 하위 호환성을 보장할 수 없는XHTML 1.1 규격을 특별한 목적 없이 사용해서 얻을 수 있는 것은 최신 규격을 지켰다는 심리적 만족 외에는 없다고 생각하므로 이 규격에 대해서는 언급하지 않겠습니다. 많은 사람들이 W3C의 권고안, 즉 표준을 완전무결한 기준으로 받아들이는데 그런 생각은 W3C의 권위가 불러오는 함정이 될 수 있습니다.

XHTML을 권장하지 않는 이유

먼저 Tommy Olsson의 글을 일부 인용하겠습니다.

XHTML과 HTML 중에서 어느 것을 선택해야 하는지에 관한 절대적 기준은 없으며, 이 문제에 관한 여러가지 기술적인 문제들을 생각했을때 간단히 답할 수 있는 문제가 아니다. 하지만 현실적으로 가장 호환성이 높은 W3C의 마지막 표준은 HTML 4.01이라 말할 수 있다. 당신이 실제로 HTML로는 불가능한 XHTML의 기능을 사용해야 하는 경우를 제외하면 기술적인 면에서 XHTML을 사용해야 할 이유는 전혀 없다.”

XHTML을 사용해서 실익을 얻으려면 XHTML과 HTML의 근본적인 차이점을 이해해야 한다. 하지만 XHTML을 제대로 사용하는 사이트를 이용할 수 있는 것은 전체 웹 사용자들의 일부일 뿐이다.”

“일부 웹 디자이너와 개발자들은 XHTML의 문법 규칙을 선호한다. 특정한 지침을 따른다면, XHTML의 기술적인 면을 전혀 사용하지 않고서도 XHTML의 문법을 사용할 수 있다. 이런 접근 방식에는 잠재적인 문제점이 있지만,<br> 태그 대신 반드시 <br /> 태그를 사용하기를 원한다면 그 방식을 따르면 된다.”

“당신의 문서가 미래의 환경에서도 유효하려면(future-proofing) XHTML과 HTML에서 어느 것을 선택하느냐 보다 Transitional 대신 Strict DOCTYPE을 사용하는 것이 훨씬 중요하다.”

그의 주장의 바탕이 되는 이유는 앞선 글에서 설명했던 브라우저의 XHTML 호환성 문제 때문인데 이에 관한 설명은브라우저가 XHTML을 해석하는 방식을 참고하시기 바랍니다.

마지막 문장에 대해서는 XHTML과 HTML의 차이에서 이미 다루었지만, 중요한 의미가 있어서 다시 한번 짚고 넘어가겠습니다.

많은 사람들이 XHTML을 사용하면 문서의 ‘구조’와 ‘표현’을 HTML보다 잘 분리해서 보다 ‘의미 있는’ 마크업을 할 수 있다고 생각하지만 이것은 사실이 아닙니다. 이런 면에서 두 규격은 서로 대등하니까요. 동일한 Strict DTD로 정의된 XHTML 1.0과 HTML 4.01 문서는 사용할 수 있는 요소(element)와 속성(attribute)에 차이가 거의 없습니다. 단지 <br> 태그 대신 <br /> 태그를 사용하는 것처럼 문법 규칙이 다를 뿐이지요.

CSS를 사용하는 것도 마찬가지입니다. XHTML과 HTML 모두 동일하게 적용되지요. 그러므로 XHTML로 가능한 문서의 ‘구조’와 ‘표현’의 분리는 HTML로도 똑같이 할 수 있습니다.

하지만 점점 더 많은 사람들이 HTML대신 XHTML을 사용해야 한다고 주장합니다. Tommy Olsson은 그 이유를 다음과 같이 밝히고 있지요.

“많은 웹 디자이너와 개발자들이 XHTML 1.0의 발표에 환호했다. XHTML은 당시에 크게 유행했던 XML이었고HTML처럼 쉽게 사용할 수 있었으며 모든 브라우저에서 잘 동작했다. 사람들은 XHTML의 확장성에서 많은 가능성을 발견했고, W3C가 더 이상의 HTML 규격은 아마도 없을 것이라고 발표하면서 XHTML이 미래 환경을 위한 유일한 대안이라고 생각하게 되었다.”

“시간이 흐르면서 XHTML 사용의 문제점과 확장성의 한계가 밝혀졌지만 XHTML에 대한 장밋빛 환상만큼 널리 알려지지는 않았다. 이 사실을 알지 못하거나 개인적인 선호 때문에 많은 사람들은 여전히 HTML보다는 XHTML을 사용해야 한다고 주장하고 있다.”

여기서 말하는 XHTML은 XML의 기능이 사용되지 않아서 HTML로도 충분히 처리가 가능한 마크업을 말합니다. XML의 기능이 꼭 필요하다면 당연히 XHTML을 사용해야겠지요. 하지만 이 글을 읽으시는 분들 중에서 XML을 사용했기 때문에 인터넷 익스플로러로는 접근할 수 없는 그런 페이지를 단 한번이라도 보신 적이 있는지요?

† 인용한 문장에서는 HTML 4.01이 W3C의 마지막 HTML 표준이 될 것이라 생각하는데, 이것은 Tommy Olsson의 원문이 2006년 6월에 씌여졌기 때문입니다. 현재 W3C에서는 HTML 5와 XHTML 5를 위한 워킹 그룹이 새로운 표준의 밑그림을 그리고 있습니다. HTML 5는 애플모질라오페라 진영의 사람들이 모여서 설립한 WHATWG에서 자신들이 개발중인 규격을 W3C의 새로운 HTML 규격을 위한 초안으로 채택해줄 것을 제안했고, W3C가 이 제안을 받아들이면서 세상에 그 이름을 알리게 되었습니다(2007년 5월). 현재 이 워킹 그룹의 편집 책임자는 구글의 Ian Hickson과 애플의 David Hyatt입니다.

그럼에도 불구하고 XHTML을 사용하는 이유

Tommy Olsson은 XHTML이 HTML과 다를 바 없으므로 HTML을 사용하는 것이 더 나은 선택이라고 주장합니다. 하지만 역설적으로 그렇기 때문에 XHTML을 사용하는 것이 아닐까요? 다시 말해서 HTML 대신 XHTML을 사용해서 얻을 수 있는 이점은 없지만, 그렇다고 해서 특별히 단점이 있는 것도 아니니까요.

XHTML을 HTML처럼 사용하는 것이 잠재적인 문제점(potential pitfall)을 안고 있다고 하지만 그것은 어디까지나 브라우저 같은 사용자 에이전트(user agent)의 내부적인 처리 방식의 문제입니다. 결과적으로 XHTML은 HTML과의 호환성을 유지하고, XHTML 문법 규칙은 혼란을 일으키지 않을 만큼 충분히 명확하기 때문에 사용자에게는 아무런 문제가 되지 않습니다.

또한 XHTML을 사용하면 HTML보다 양식화된(well-formed) 문서를 작성할 수 있는데 이것은 브라우저가 아닌 사용자 입장에서 특히 유익합니다. 브라우저는 </p> 태그가 없어도 문단이 어디서 끝나는지 명확하게 알 수 있지만, 사용자는 그것을 알기가 어려우니까요.

물론 HTML을 사용해도 동일하게 양식화(well-formed)된 문서를 작성할 수 있습니다. </p> 태그는 생략할 수 있는 것이지 생략해야 하는 것이 아니기 때문입니다. 하지만 XHTML을 사용하면 마크업 검증기(validator)가 문서의 양식을 더 꼼꼼하게 확인합니다. 따라서 XHTML 마크업을 작성하고 검증해보는 것이 양식화된 마크업을 익히는데 유리합니다.

미래의 웹 환경이 어떻게 달라질지 예상하는 것은 어렵습니다. 하지만 단시일 내에 모든 브라우저들이 완벽하게 XML을 지원하리라고는 믿지 않습니다. 개인적으로는 XHTML 문서를 나타내는 .xhtml 확장자가 지금의 .html 확장자 만큼 익숙해져야 XHTML 문서가 그 힘을 발휘할 수 있다고 생각하는데 그 때를 대비해서 XHTML을 써야한다고 주장하는 것이 아닙니다. 앞서 말씀드렸듯이 지금 작성되는 대부분의 XHTML 문서에는 XML 만의 기능이 들어가 있지 않으니까요. XHTML의 하위 호환성을 고려했을 때 HTML 대신 사용해도 무방하다는 것이 제 의견의 요지입니다.

마치면서

XHTML과 HTML 규격의 차이점을 다루는 글을 쓰게 된 동기는 ‘웹 표준’과 XHTML 사용을 동일하게 받아들이는 일부의 시각 때문입니다. HTML 4.01 규격도 엄연히 W3C가 제정한 표준 권고안임에도 불구하고 XHTML과 CSS를 사용해야만 웹 표준을 지킬 수 있고, 그것이 무조건 더 좋은 방법이라고 생각하는 분들이 있는데 절대적으로 틀린 생각입니다.

웹 표준을 잘 지키고 그 장점을 누리기 위해서는 XHTML과 HTML의 차이가 아니라 Strict와 Transitional DTD의 차이를 아는 것이 훨씬 더 중요합니다. 이 주제에 관해서는 나중에 다루도록 하고, XHTML과 HTML 규격의 차이점에 관한 글은 이것으로 모두 마칩니다.


출처 : http://blog.wystan.net/2007/05/27/why-xhtml

반응형

'UI' 카테고리의 다른 글

XHTML과 HTML의 차이  (0) 2014.04.24
반응형

차이를 찾다가... 좋은 글이라 퍼옵니다.



XHTML과 HTML은 현재 가장 널리 사용되는 웹 문서 규격입니다. 이름에서도 알 수 있듯이 XHTML은 기존에 사용되던 HTML 규격이 가진 문제점을 극복하고, 보다 다양한 분야에 응용될 수 있도록 해주는 여러가지 확장된 기능을 포함하고 있습니다.

HTML을 XML 바탕으로 새롭게 구성(reformulation)한 XHTML은 CSS와 함께 최근에 많은 관심을 받고 있는 ‘웹 표준’의 중요한 요소가 되었습니다. 하지만 XHTML이 XML을 기반으로 만들어졌고, 이 XML을 모든 브라우저가 지원하지 않는다는 현실적인 문제 때문에 XHTML과 HTML이 사실상 큰 차이 없이 사용된다고 주장하는 사람들도 많습니다.

이런 시각을 다루는 좋은 글이 있어서 번역해서 소개합니다. 내용이 많아서 세 번으로 나눠서 포스팅하려고 하는데 글의 전문성에 비해 제 이해가 많이 부족하고, 원문을 요약한 것이어서 그 내용을 완벽하게 전달하는데 한계가 있으니 감안해서 보시기 바랍니다.

Tommy Olsson이 쓴 원문은 Site Point 포럼에 올라온 FAQ About XHTML vs HTML이니 참고하시고, dagger 마크(†)로 시작하는 단락은 원문에는 없는 보충 설명입니다. 이 글의 저작권은 원문의 저작자인 Tommy Olsson과Site Point에 있으며, 블로그 전체에 적용되는 CCL보다 우선적으로 적용됩니다.

XHTML과 HTML의 차이점

  • XHTML이 XML 문법을 따르므로 HTML과 문법 규칙이 약간 다르다.
  • XHTML을 사용하면 할 수 있으나, HTML로는 불가능한 일이 있다.
  • HTML을 사용하면 할 수 있으나, XHTML로는 불가능한 일이 있다.
  • CSS를 이해하는 방식에 차이가 있다.
  • 클라이언트 쪽의 스크립트(예: 자바 스크립트)를 다루는 방식에 차이가 있다.

첫 번째로 언급한 문법적인 차이를 다루는 문서는 많기 때문에 자세한 설명을 하지 않겠습니다.

XHTML을 사용하면 할 수 있으나, HTML로는 불가능한 일
  • CDATA 섹션(<![CDATA[ … ]]>) 사용.
    이 섹션 안의 문자들은 태그로 처리되지 않기 때문에 따로 이스케이프(escape) 해 줄 필요가 없다.
  • processing-instruction 사용. 예를 들어 XML 문서에 스타일시트를 연결시킬 수 있다. 
    <?xml-stylesheet type="text/css" href="style.css" media="screen"?>
  • 다른 XML 이름 영역(namespace)에 있는 요소(element)들을 포함시킬 수 있다.
  • &apos; 캐릭터 엔티티(character entity)를 사용할 수 있다.
HTML을 사용하면 할 수 있으나, XHTML로는 불가능한 일
  • 기존 HTML에서 사용하던 <!-- … --> 코멘트로 스타일이나 스크립트의 일부를 주석 처리할 수 없다.
  • 문서를 읽고 있는 도중에는 페이지의 일부를 동적으로 생성할 수 없다(예: document.write() 사용).
  • &nbsp; 같은 named entity를 사용할 수 없다. 미리 정의된 &lt;, &gt;, &amp;, &quot;는 사용 가능.
  • 자바 스크립트에서 .innerHTML 속성을 사용할 수 없다.

† 위 두 문단 중 첫 번째 문단은 XHTML로 할 수 있는 일을, 두 번째 문단은 XHTML로 불가능한 일을 열거하고 있습니다(2009.10.27).

CSS를 이해하는 방식의 차이
  • CSS의 Element type 선택자가 대문자와 소문자를 구별한다(case-sensitive).
  • HTML에서는 BODY 요소의 background-color, background-image, overflow 속성이 최상위 요소(HTML)에도 적용되지만 XHTML에서는 적용되지 않는다.

HTML의 일부 시작 태그는 명시적으로 지정하지 않아도 CSS가 적용된다. 예를 들어서 표(table) body 태그의 헤더 셀(header cell)에 스타일을 적용하려고 할 때 다음과 같이 CSS 규칙을 지정할 수 있다.

tbody th { text-align: left }

HTML 문서에서는 <tbody>와 </tbody> 태그를 마크업하지 않아도 이 CSS 스타일이 적용되지만 XHTML에서는 태그를 마크업하지 않으면 적용되지 않는다.

클라이언트 쪽의 스크립트(예: 자바 스크립트)를 다루는 방식의 차이
  • document.write() 메소드가 적용되지 않는다.
  • createElement() 같은 DOM 메소드는 반드시 이름 영역(namespace)에 대응되는 메소드로 바꿔줘야 한다(예: createElementNS() 사용).
  • 표준이 아닌 .innerHTML 속성을 사용할 수 없다.
  • CSS에서와 마찬가지로 명시적이지 않은 요소(element)에 관한 문제가 자바 스크립트에도 적용된다.

XHTML이 HTML보다 더 엄격한가(strict)?

그렇지 않다. XHTML을 포함하는 XML의 문법 규칙이 HTML에 비해 더 단순하고, 일관적이지만 마크업이 유효(valid)하다면 XHTML과 HTML은 동일하게 해석(parsed)된다.

† 이 질문에서 말하는 엄격함은 문법 규칙만을 고려한 것으로 보입니다. 단순히 문법적인 면을 따져봤을 때에는 XHTML이 HTML보다 엄격한 것이 분명합니다. 하지만 원문에서 그렇지 않다고 말한 것은 브라우저가 XHTML을 HTML과 동일하게 해석하기 때문이라고 생각되네요.

그는 문단 태그(<p>)를 예로 들었는데 HTML에서는 문단을 </p> 태그로 닫지 않아도 어느 곳에서 그 태그가 닫혀야 하는지 명백하게 판단이 가능합니다. XHTML에서 </p> 태그를 생략하면 검증기(validator)는 에러를 찾아내지만 실제로 브라우저는 아무런 문제 없이 HTML과 동일한 결과를 출력하지요. 왜냐하면 거의 대부분의 XHTML 문서가 실제로는 HTML로 브라우저에게 인식되기 때문입니다. 이것은 브라우저의 XML 지원과 Content-Type에 관련된 문제인데 이 부분에 대해서는 추후에 다루겠습니다.

또한, ‘strict’라는 단어에는 ‘엄밀(정밀)하다’는 뜻도 있습니다. 이런 의미로 해석할 경우에는 HTML이 XHTML보다 정밀하다는 표현이 맞습니다. HTML을 해석하려면 생략된 태그를 판단하는 추가적인 로직이 필요하니까요. 원문에는 HTML의 문법 규칙이 XHTML보다 복잡(more complicated)하다고 표현하고 있습니다. 이 부분에 관한 자세한 내용은 원문에 달린 댓글을 참고하시기 바랍니다.

XHTML이 HTML보다 더 의미 있는 마크업인가(semantic)?

그렇지 않다. XHTML 1.0 규격은 HTML 4.01 규격을 새롭게 구성한 것이므로 두 규격은 똑같은 요소(element)와 속성(attribute)을 가지며 세 가지 문서 타입(DTD)도 동일하다. 의미론적으로는 두 규격에 아무 차이도 없다.

† 이 글을 쓰게 된 동기 중의 하나가 이 문제 때문입니다. 많은 사람들이 XHTML이 HTML보다 더 ‘의미 있는’ 규격이라고 생각하는데 실제로는 차이가 없습니다. 오히려 XHTML Transitional 규격과 HTML Strict 규격을 비교해보면HTML Strict 규격이 ‘구조’와 ‘표현’을 훨씬 엄격하게 구분하므로 보다 의미 있는 규격입니다. 따라서 HTML Strict DTD로 작성된 문서가 XHTML Transitional 문서보다 ‘웹 표준’을 보다 잘 준수한다고 말할 수 있습니다.

CSS는 XHTML과 HTML에 모두 다 적용되는가?

그렇다. CSS를 XHTML에서만 사용할 수 있다고 생각하는 사람들이 있는데 이것은 분명히 잘못된 정보이다. 최초의CSS 규격은 1996년에 만들어졌고, XHTML은 그 후 사 년 후에야 만들어졌다.

DOCTYPE 선언은 어떻게 사용되는가?

문서 맨 앞에 선언되는 DOCTYPE이 브라우저 같은 클라이언트 프로그램(user agent)에게 해당 문서가 XHTML이라는 것을 알려주는 역할을 한다고 생각하는 사람들이 있지만 이것 역시 사실이 아니다. DOCTYPE 선언이 만들어진 원래의 유일한 목적은 마크업을 검증하기 위한 것이며, 브라우저는 마크업을 검증할 필요가 없으므로 이 선언을 무시하고 마크업을 해석한 다음 화면에 출력했다.

하지만 매킨토시 버전의 인터넷 익스플로러 5.0(IE5/Mac)이 발표되면서 처음으로 DOCTYPE 선언을 브라우저가 이용하게 되었는데, IE5/Mac 브라우저는 구 버전이나 형제 격인 윈도우즈 버전의 브라우저보다 웹 표준을 지원하는 면에서 큰 향상을 가져왔다.

웹 표준을 보다 잘 지키면서 정확하지 않은 IE의 CSS 렌더링에 맞춰서 개발된 많은 웹 문서들에 대한 호환성을 유지하기 위해서 DOCTYPE이 사용되기 시작했다. 이 기능은 이후 인터넷 익스플로러 6.0 버전에 도입되었고, 최근에 사용되는 대부분의 브라우저에는 이 기능이 포함되어 있다.

현재 DOCTYPE 선언은 두 가지 기능을 한다. 첫 번째는 검증기(validator)가 어떤 기준으로 마크업의 유효성을 확인해야 하는지에 관한 정보를 제공하는 것이고, 두 번째는 브라우저에게 어떤 렌더링 모드를 사용할지 알려주는 기능이다. 이것은 XHTML과 HTML의 차이와는 근본적으로 아무 관련이 없다. 하지만 XHTML을 올바르게 지원하는 브라우저는 XHTML을 엄격한 표준(strict standard) 모드로 렌더링하는데 그러기 위해서는 XHTML을 올바르게 브라우저에게 인식시켜야 한다.


XHTML과 HTML의 차이에 관해서는 이것으로 마치겠습니다. 원문의 정보가 100% 옳다고 확신할 수는 없지만 100개 이상 달린 댓글을 보면 어느 정도 검증된 문서라고 판단할 수 있으리라 생각합니다.

다음 글에서는 브라우저가 왜 대부분의 XHTML 문서를 HTML과 동일하게 받아들이지는 알아보도록 하지요. 앞서 언급했던 브라우저의 XML 지원과 Content-Type에 관한 문제입니다.

출처 : http://blog.wystan.net/2007/05/24/xhtml-vs-html


반응형

'UI' 카테고리의 다른 글

XHTML을 사용하는 이유  (0) 2014.04.24

+ Recent posts