달력

5

« 2024/5 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
.. .. ..

URL : http://www.infoq.com/articles/spring-2.5-part-1 번역본


JSR(Java Specification Request)-250 어노테이션에 대한 스프링 지원사항.

 

자바 플랫폼을 위한 공통 어노테이션은 자바 EE 버전 5와 함께 소개되었고 자바 SE 버전 6에서 본격화되었다. 2006 5 BEA 시스템즈는 인젝션,인터셉션,트랜잭션을 위한 JSR-250 어노테이션과 EJB 3 어노테이션(JSR-220)에 대한 지원을 포함하는 자바 EE 5 프로그래밍 모델의 스프링 기반 실행을 제공한 Pitchfork 프로젝트에 사용되었던 인터페이스21을 발표하였다.

 현재 버전 2.5 스프링 프레임워크 core @Resource,@PostConstruct,@PreDestroy를 지원한다. 이러한 스프링 어노테이션은 어떠한 환경에서도 지원된다. 어플리케이션 서버가 있든 없든 심지어 통합 테스팅 환경에서도 지원된다. 이러한 기능은 단지 스프링 post-processor를 등록하는것만으로 가능해진다.

 

<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>

 

@Resource 어노테이션

 

@Resource 어노테이션은 named resource DI(Dependency Injection)을 가능케한다.

이것은 전형적으로 자바 EE 어플리케이션내에서 JNDI context의 객체 범위로 번역된다.

스프링은 JNDI lookups를 통해 객체를 분석하는 용도로 @Resource 어노테이션을 사용하는 것을 지원하지 않는다. 그러나 기본적으로 @Resource 어노테이션에 기입된 이름과 일치하는 bean name(스프링에 의해 관리되는 객체)이 추가될 것이다.

다음의 예를 보면 스프링은 어노테이션 기능을 사용한 set메소드에서 빈 이름이 dataSource인 스프링에 의해 관리되는 객체에 대한 참조는 무시한다.

 

@Resource(name="dataSource")

 public void setDataSource(DataSource dataSource) {
  
this.dataSource
= dataSource;
}

 

 

 

 

 

직접적으로 필드에 @Resource 어노테이션을 기입하는 것도 가능하다. set메소드를 노출시키지 않음으로써 코드는 더 간결해지고 또한 불변성이라는 추가적인 이점도 제공받는다. 아래에 설명되어진 것과 같이 @Resource 어노테이션은 명시적인 문자열 값조차도 필요로 하지 않는다. 아무것도 주어지지 않았을 때 필드의 이름이 기본으로 사용된다.

 

@Resource
private DataSource dataSource; // inject the bean named 'dataSource'

 

set메소드에 적용시켰을 때 기본이름은 그에 대응되는 프로퍼티에 의해 결정된다. 다시 말해서 setDataSource이라는 이름의 메소드는 프로퍼티의 이름을 dataSource로 결정한다.

 

private DataSource dataSource;
@Resource
public void
setDataSource(DataSource dataSource) {
  
this.dataSource
= dataSource;
}

 

기본이름을 위해 스프링에 의해 관리되는 객체가 발견되지 않은 상태에서 주어진 이름없이 @Resource 어노테이션을 사용한다면 주입 기법은 타입일치에 의지할 것이다. 따라서 의존성 타입에 일치하는 스프링에 의해 관리되는 객체가 주입될것이다.

 이러한 특징은 CommonAnnotationBeanPostProcessorfallbackToDefaultTypeMatch 프로퍼티 값을 false(기본값은 true)로 설정함으로써 비활성화시킬수 있다.

 

<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor">
   <property name="fallbackToDefaultTypeMatch" value="false"/>
</bean>

 

위에서 언급한것처럼 스프링은 @Resource으로 처리된 의존성을 분석할 때 JNDI-lookups를 지원하지 않는다. @Resource로 처리된 모든 의존성을 위해 JNDI-lookups를 사용하기 위해서는 CommonAnnotationBeanPostProcessor alwaysUseJndiLookup플래그 값을 true로 설정해야 한다(기본값은 false).

 

 

<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor">
   <property name="alwaysUseJndiLookup" value="true"/>
</bean>

 

다른대안으로 resource-ref-mappings로서 짜여진 세계적인 JNDI names에 기반을 둔 lookup을 활성화시키기 위해서 @Resource 어노테이션 내에 mappedName속성을 설정해야 한다. 실제로 대상객체가 JNDI자원일 때 스프링에 의해 관리되는 객체를 참조사항으로 사용하는 것은 추천하는 방법이며 이로 인해 간접적인 조치와 향후 보다 적은 결합을 제공한다.

JNDI lookup을 다루기 위해 스프링 2.0부터 유용한 네임스페이스를 추가함으로써 스프링에 정의된 빈은 간결하고 명확해진다.

<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/petclinic"/>

 

이러한 접근의 이점은 간접적 조치는 보다 큰 범위의 배치 유연성을 제공한다라는 점이다.예를 들면 독립 시스템 테스트 환경은 JNDI등록을 필요로 하지 않는다. 이러한 경우에 다음과 같은 빈 정의가 시스템 테스트 환경설정에서 대체안으로 주어질 수 있다.

<bean

 id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"
      p:driverClassName="${jdbc.driverClassName}"
      p:url="${jdbc.url}"
      p:username="${jdbc.username}"
      p:password="${jdbc.password}"/>

 

위의 예에서는 실질적인 JDBC연결속성이 주어진 ${placeholder}토큰들과 매치되는 키값들이 있는 속성파일로부터 분석된다. 이것은 PropertyPlaceholderConfigurer로 불려지는 스프링 BeanFactoryPostProcessor실행을 등록함으로서 이루어진다. 이것은 환경설정에 설정되어 있는 것보다 더 자주 변화할 필요가 있는 속성들을 구체화시키는데에 흔히 사용되어지는 기법이다.

 

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
   <property name="location" value="classpath:jdbc.properties"/>
</bean>

 

스프링 2.5에서 context 네임스페이스의 추가로 인해 property placeholder 환경설정에 더 명확한 대안이 가능해진다.

 

<context:property-placeholder location="classpath:jdbc.properties"/>

 

라이프 사이클 어노테이션 : @PostConstruct @PreDestroy

 

@PostConstruct @PreDestroy 어노테이션은 스프링 초기화 작업을 수행할 메소드와 컨테이너에서 객체를 제거하기 전에 호출되는 콜백함수들을 가동시키는데에 각각 사용된다.

그러나 이러한 특징이 스프링 2.5 이전 버전에서 이와 같은 콜백함수들을 제공하는 두가지 옵션을 대신하지는 않는다. 첫번째 옵션은 스프링의 InitializingBean DisposableBean인터페이스 중 한쪽 또는 양쪽다 실행하는 것이다. 각각의 인터페이스는 하나의 콜백메소드( 각각 afterPropertiesSet() destroy() )실행을 필요로 한다. 인터페이스를 기반으로 한 접근은 이러한 인터페이스를 실행하는 모든 스프링에 의해 관리되는 객체를 자동적으로 인식하는 스프링의 능력을 이용한다. 따라서 다른 추가적인 환경설정을 필요로 하지 않는다. 반면에 스프링의 주요 목적은 가능한한 비침해적인 것에 초점을 두고 있다. 따라서 특정 스프링 인터페이스를 실행하는 것 대신에 많은 스프링 사용자들은 특정 스프링 인터페이스의 초기화와 소멸 메소드들을 제공하는 두번째 옵션을 이용해왔다. 조금 덜 비침해적이기는 하지만 이 접근의 결점은 빈 엘리먼트에 'init-method''destroy-method'(양쪽다 또는 한가지) 속성을 명시적으로 선언할 필요가 있다는 것이다. 개발자의 관리영역 외부코드에서 콜백함수들이 호출될 필요가 있을 때 뚜렷한 환경설정이 때로는 필요하다. PetClinic어플리케이션은 이러한 시나리오를 증명해준다. PetClinic어플리케이션이 자신의 JDBC 환경설정으로 실행될 때 세번째 공용 DataSource가 사용되고 'destroy-method'는 명시적으로 선언된다. 또한, 독립 커넥션 풀 DataSource는 여전히 dataSource를 위한 또 하나의 배치옵션이라는 점과 어떠한 코드 변화도 필요로 하지 않는다는 점을 주의해라.

 

<bean id="dataSource"
            class="org.apache.commons.dbcp.BasicDataSource"
            destroy-method="close"

            p:driverClassName="${jdbc.driverClassName}"
            p:url="${jdbc.url}"
            p:username="${jdbc.username}"
            p:password="${jdbc.password}"/>

 

 

스프링 2.5에서 객체가 초기화 콜백 메소드의 호출을 필요로 한다면 그 메소드는 @PostConstruct 어노테이션으로 처리될 수 있다. 예를 들면, 시작할 때 파일 목록을 올리는 것을 시작할 필요가 있는 백그라운드 작업을 상상해보아라.

 

public class FilePoller {
 
   @PostConstruct

  
public void
startPolling() {
         ...
   }
   ...
}

 

간단하게 말해서, 스프링에 의해 관리되는 객체에서 @PreDestroy로 처리된 메소드는 그 객체를 관리하는 어플리케이션 컨텍스트가 닫힐 때 호출될 것이다.

 

public class FilePoller {
    @PreDestroy

  
public void
stopPolling() {
           ...
   }
   ...
}

 

JSR-250 어노테이션을 위한 추가적인 지원과 함께 현재 스프링 2.5는 이전의 두가지 라이프 사이클 메소드 양자의 강점을 결합시킨다. 메소드에 @PostConstruct @PreDestroy를 기입하는것은 스프링 관리 컨텍스트내에 있는 콜백함수들을 호출하기에 충분하다. 다시 말해서 추가적인 XML기반의 환경설정이 불필요하다. 동시에 어노테이션은 자바언어의 일부이다.(그리고 심지어는 자바 SE 버전 6에 포함된다.) 그러므로 구체적인 스프링 개입은 필요없다. 어노테이션은 다른 환경내에서 이해되어야만 의미론을 지적하는 추가적 이점도 가지고 있고, 시간이 경과할수록 자바 개발자들은 제3자 라이브러리에서 더 빈번히 사용된 이러한 어노테이션들을 보게 될것이다. 결국, 어노테이션 기반의 라이프 사이클 콜백함수들의 한가지 흥미로운 점은 하나 이상의 메소드가 둘 중의 어느 한쪽 어노테이션을 지닐수 있고, 어노테이션 처리된 모든 메소드들은 호출될것이라는 점이다. 위에 서술된 @Resource, @PostConstruct, @PreDestroy 어노테이션들의 모든 기능을 활성화시키기 위해서 이전에 보여준 것처럼 스프링의 CommonAnnotationBeanPostProcessor을 위한 하나의 빈 정의를 제공한다. 하나의 엘리먼트가 CommonAnnotationBeanPostProcessor를 등록하지 않는 것을 포함하여 스프링 2.5에서 더 정확한 옵션은 새로운 context 네임스페이스를 사용하는 것이다.

 

<context:annotation-config/>

 

그러나 아래 섹션에 서술된것처럼 autowiring기능을 가능하게 할 것이다. 심지어 CommonAnnotationBeanPostProcessor@WebServiceRef@EJB 어노테이션을 지원한다. 이러한것들은 기업 통합을 위한 스프링 2.5의 새로운 특징을 싣고 있는 이 연속출판물의 세번째 기사에 잘 나와있다.

 

Fine-Grained Autowiring with Annotations

 

스프링의 autowiring지원 문서는 종종 autowiring기법의 사소한 경고를 언급한다. 스프링 2.5 이전 버전에서는 autowiring은 다른 많은 접근(생성자, 타입 set 메소드, 이름 set 메소드,  자동검색(스프링이 생성자나 타입 set 메소드 둘 중 하나를 autowire하는 것을 선택) )으로 설정될 수 있었다. 이러한 다양한 옵션들은 높은 등급의 유연성을 가지고 있다. 그러나 이러한 옵션들이 뛰어난 관리능력을 자랑하지는 않는다. 다시 말해서 스프링 2.5버전 이전에는 객체의 set메소드의 명확한 부분을 autowire하는 것 또는 타입에 의한 몇가지 속성과 이름에 의한 다른것들을 autowire하는 것이 가능하지 않았다. 결과적으로 많은 스프링 사용자들은 프로토타이핑과 테스팅에 적합한 autowiring의 이점들을 인지해왔다. 그러나 이러한 이점들이 생산에 있어서 유지보수 시스템에 봉착하면 대부분의 사람들은 명확한 환경설정에 추가된 여러가지 것들이 꽤 가치가 있는 설명이라는점에 동의한다.

 그러나 극적으로 스프링 2.5는 전망을 변화시킨다. 위에 서술된것처럼 autowiring선택은 JSR-250 @Resource 어노테이션이 각각의 메소드나 필드에 이름붙은 자원들의 autowiring을 가능하게 하는 지원을 받으면서 확장되어왔다. 그러나 @Resource 어노테이션은 홀로 몇가지 한계점을 가지고 있다. 그 결과 스프링 2.5는 추가적으로 제어수준을 높이기 위해 @Autowired 어노테이션을 소개한다. 이 부분에서 서술되어진 기능들을 활성화시키기 위해  하나의 빈 정의를 등록하라.

 

<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor/>

 

 

다른방도로 context 네임스페이스는 이전에 우리에게 보여준 것처럼 더 정확한 대안을 제공한다. 이것은 이 기사에서 논의되었던 post-processor(

AutowireAnnotationBeanPostProcessor CommonAnnotationBeanPostProcessor)과 스프링 2.0에서 소개되었던 어노테이션 기반 post-processor(

RequireAnnotationBeanPostProcessor PersistenceAnnotationBeanPostProcessor)를 활성화시킬것이다.

 

<context:annotation-config/>

 

@Autowired 어노테이션으로 인해 타입매치에 의한 의존성 주입이 가능해졌다. 이 점은 필드와 생성자 그리고 메소드들에 적용된다. 사실상, autowired 메소드들은 set메소드일 필요는 없고 심지어 여러 개의 파라미터를 받아들일 수 있다. 다음은 사용가능한 용법이다.

 

@Autowired
public void setup(DataSource dataSource, AnotherObject o) { ... }

 

기본적으로, @Autowired 어노테이션으로 표시된 의존성들은 필요한것으로 취급된다. 그러나 required속성을 false값으로 설정함으로서 @Autowired 어노테이션으로 표시된 의존성의 어떤것이든 마음대로 선언하는 것이 가능하다.

 다음의 예와 같이 SomeStrategy타입의 스프링에 의해 관리되는 객체가 context안에서 발견되지 않는다면 DefaultStrategy가 사용될 것이다.

 

@Autowired(required=false)
private SomeStrategy strategy = new DefaultStrategy();

 

스프링 컨텍스트가 예상된 타입의 한가지 객체보다 더 많은 객체를 포함하고 있을 때 타입에 의한 autowiring은 분명히 모호함을 발생킬 수 있다.

기본적으로, 필요한 의존성을 위해 하나의 빈이 없다면 autowiring기법은 동작하지않을것이다. 마찬가지로 임의의 모든 속성들에 대해 한가지 이상의 후보자가 존재하다면 autowiring기법은 동작하지 않을것이다. (후보자가 없거나 임의로 선택가능한 후보자가 존재하다면 autowiring기법은 간단히 그 속성들을 스킵할 것이다.) 이러한 충돌을 피하기 위한 여러가지 환경설정 옵션이 있다.

컨텍스트내에 주어진 타입의 primary 인스턴스가 있을 때 그 타입을 위한 빈 정의는 primary속성을 포함해야 한다. 이러한 접근은 다른 인스턴스들이 컨텍스트안에서 유효할 때 잘 동작한다. 그러나 비primary 인스턴스들은 항상 정확하게 설정된다.

 

<bean id="dataSource" primary="true" ... />

 

더 엄격한 관리가 필요할 때 모든 autowired 필드,생성자 인수,메소드 파라미터는 추가적으로 @Qualifier 어노테이션 처리된다. 스프링이 이름에 의한 매치를 시도할 경우 Qualifier는 문자열값을 포함한다.

 

@Autowired
@Qualifier("primaryDataSource")

private DataSource dataSource;

 

@Qualifier가 따로 분리된 어노테이션으로 존재하는 주원인은 @Autowired 어노테이션이 생성자나 그 자신의 메소드에서 유효할 때 생성자 인수나 메소드 파라미터에 적용될 수 있도록 하기 위해서이다.

 

@Autowired
public void setup(@Qualifier("primaryDataSource") DataSource dataSource, AnotherObject o) { ... }

 

@Qualifier가 따로 분리된 어노테이션이라는 사실은 심지어 커스터마이제이션에 관련된 더 많은 이점을 제공한다. 또한 사용자 정의 어노테이션은 autowiring프로세스에서 qualifier의 역할을 수행한다. 이것을 충족시키기 위한 가장 간단한 방법은 메타 어노테이션으로서 @Qualifier와 커스텀 어노테이션을 기입하는것이다.

 

@Target({ElementType.FIELD,ElementType.PARAMETER,ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier

public @interface VetSpecialty { ... }

 

커스텀 어노테이션들은 임의로 이름에 의한 매치값을 포함할 수도 있다. 그러나 더 흔하게 marker 어노테이션으로서 사용되거나 qualifier 프로세스에 몇가지 추가적인 의미를 제공하는 값을 정의한다. 예를 들면 아래의 인용구는 타입이 일치되는 것들 중에서 적합한 후보자를 가지고 autowire처리되어야만 하는 필드를 묘사한다.

 

 

@Autowired
@VetSpecialty("dentistry")

private Clinic dentistryClinic;

 

이러한 의존성 해결책으로서 XML 환경설정을 사용할 때 qualifier 부엘리먼트들은 빈정의에 추가된다. component-scanning부분에서 비XML 대체안이 소개될것이다.

 

<bean id="dentistryClinic" class="samples.DentistryClinic">
<qualifier type="example.VetSpecialty" value="dentistry"/>
</bean>

 

@Qualifier에 있는 모든 의존성을 피하기 위해서라면 스프링 컨텍스트에 CustomAutowireConfigurer빈을 정의하고 모든 커스텀 어노테이션 타입들을 직접적으로 등록하라.

 

<bean class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
   <property name="customQualifierTypes">
              <set>
                          <value>example.VetSpecialty</value>
              </set>
   </property>
</bean>

 

커스텀 qualifier가 명확하게 선언되었기 때문에 @Qualifier 메타 어노테이션은 더 이상 필요치 않다.

 

@Target({ElementType.FIELD,ElementType.PARAMETER,ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface VetSpecialty { ... }

 

관련문서에서는 심지어 AutowiredAnnotationBeanPostProcessor를 설정할 때@Autowired 어노테이션 자체를 위치시키는 것도 가능하다고 말한다.

 

<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor">
<property name="autowiredAnnotationType" value="example.Injected"/>
</bean>

 

대개의 경우에 이름에 의한 매치나 다른 의미값들의 옵션들로 결합된 marker 커스텀 어노테이션을 정의하는 능력은 autowiring프로세스의 좋은 관리를 해내기에 충분해야한다. 그러나 스프링은 qualifier 어노테이션들에서 많은 임의의 속성을 지원한다. 예를 들면, 다음은 매우 좋은 qualifier의 가상의 예이다.

 

@SpecializedClinic(species="dog", breed="poodle")

private Clinic poodleClinic;

 

커스텀 qualifier 실행은 이러한 속성들을 정의한다

 

@Target({ElementType.FIELD,ElementType.PARAMETER,

ElementType.TYPE, ElementType.ANNOTATION_TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Qualifier

public @interface SpecializedClinic {
 
   String species();

 
  
String breed();

}

 

커스텀 qualifier의 속성들은 XML 빈 정의내에서 qualifier 어노테이션의 attribute 부엘리먼트에 매치된다. 이러한 요소들은 key/value쌍들을 제공하기 위해 사용된다.

 

<bean id="poodleClinic" class="example.PoodleClinic">
   <qualifier type="example.SpecializedClinic">
              <attribute key="species" value="dog"/>

<attribute key="breed" value="poodle"/>
 </qualifier>

</bean>

 

여태까지 설명된 모든 autowiring은 하나의 객체를 위한것이지만 collection도 지원받는다. 언제든지 컨텍스트내에서 모든 확실한 타입의 스프링에 의해 관리되는 객체들을 얻는것은 필요하고 다만 @Autowired 어노테이션을 엄격하게 type이 설정된 collection에 추가해라.

 이 부분에서 주목할만한 가치가 있는 마지막 한가지 특징은 스프링의 Aware 인터페이스를 대신하는 autowiring의 사용이다. 스프링 2.5 이전 버전에서는 객체가 스프링 컨텍스트의 ResourceLoader에 대한 참조를 필요로 한다면 그 객체는 스프링이 setResourceLoader(ResourceLoader resourceLoader) 메소드를 이용하여 이러한 의존성을 제공하는 것을 허용하기 때문에 ResourceLoaderAware를 실행할 수 있다.
 
이와 같은 기법은 스프링 관리 MessageSource와 심지어 그 자신의 ApplicationContext에 대한 참조를 얻는데에도 적용된다. 스프링 2.5 사용자들을 위해서 이러한 기법은 지금 autowiring을 통하여 완벽하게 지원받는다.(주의 : 스프링에 뚜렷이 나타난 이러한 의존성들의 결과는 항상 조심스럽게 다루어져야 하고 일반적으로 비즈니스 로직과 확실하게 분리된
infrastructure코드 안에서만 사용되어야 한다. )

 

@Autowired
private
MessageSource messageSource;
 
@Autowired
private
ResourceLoader resourceLoader;
 
@Autowired
private ApplicationContext applicationContext;

 

 

Auto-Detection of Spring Components

 

 스프링 버전 2.0을 시작으로 스프링은 데이터 액세스 코드 표시로 적합한 @Repository 어노테이션을 포함하고 있는 stereotype 어노테이션들의 개념을 소개했다. 스프링 2.5는 통상적인 3-tier 아키텍처(데이터 액세스 객체,서비스,웹 컨트롤러)를 위해 지정된 역할을 완성하기 위해 두가지 새로운 어노테이션(@Service @Controller)을 추가했다. 또한 스프링 2.5는 다른 stereotype들이 논리적으로 확장시키는 제네릭 @Component 어노테이션을 소개한다. 정확하게 어플리케이션 역할을 지시함으로서 이러한 stereotypes는 스프링 AOP와 이러한 역할에 기반을 두고 어노테이션 처리된 객체들에 추가적인 기능을 제공하는 post-processors의 사용을 촉진한다. 예를 들면 스프링 2.0@Repository 어노테이션을 실행하는 모든 객체들에 적합한 데이터 액세스 예외 번역을 자동적으로 가능하게 하는PersistenceExceptionTranslationPostProcessor을 소개했다.

또한 이와 동일한 어노테이션들은 스프링의 또 하나의 새로운 특징(클래스패스에 있는 컴포넌트들의 auto-detection)과 관련하여 사용될 수 있다. 전통적으로 XML이 스프링 메타데이터를 위해 가장 인기있는 형식이었음에도 불구하고, 이것은 유일한 선택사항이 아니다. 사실, 스프링 컨테이너의 내부 메타데이터 표현은 순수 자바이고 XML이 스프링에 의해 관리되는 객체를 정의하기 위해 사용될 때 이러한 정의들은 인스턴스화 과정이전에 해석되고 자바 객체들로 변환된다. 스프링 2.5의 한가지 중요한 새로운 능력은 소스레벨 어노테이션으로부터 메타데이터를 읽는 것을 지원한다는 점이다. 이제까지 기술된 autowiring기법은 의존성들을 주입시키는 기능을 하는 어노테이션 메타데이터를 사용한다. 그러나 여전히 각 스프링에 의해 관리되는 객체의 실행 클래스들을 제공하기 위해 적어도 최소의 빈 정의 등록을 필요로 한다. Component scanning 기능은 XML에서 최소한의 빈 정의 필요성마저도 없앨 수 있다.

위에서 보여진 바와 같이, 스프링의 어노테이션 주도의 autowiring은 좋은 제어를 희생시키는 것없이 XML의 양을 상당히 줄일 수 있다. Component 검색기법은 추가적으로 이러한 기법을 가지고 있다. XML에 있는 환경설정을 완벽하게 탈취하는 것은 필요하지 않다. 오히려 component scanning은 전반적인 환경설정을 간단히 하기 위해 XML 메타데이터를 옆에 두고 동작할 수 있다. XML을 결합하는 이 가능성과 어노테이션 주도의 기법은 PetClinic 샘플 어플리케이션 2.5 버전의 설명에서 볼 수 있듯이 균형잡힌 접근인 셈이다.

그 점에서 하부구조의 components(데이터 소스, 트랜잭션 매니저등)가 위에서 설명한것과 같이 구체화된 프로퍼티들과 함께 XML에서 정의된다. 데이터 액세스 tier 객체들은 또한 XML에서 부분적으로 정의된다. 그러나 그것들의 환경설정은 의존성 주입을 간단히 하기위해@Autowired 어노테이션을 이용한다. 결국, tier 컨트롤러들은 XML에서 명확하게 전혀 정의되지 않는다. 대신에 모든 웹 컨트롤러들의 auto-detection을 가동시키기 위해 아래와 같은 환경설정이 사용된다.

 

<context:component-scan base-package="org.springframework.samples.petclinic.web"/>

 

base-package 속성이 주어진다는 점을 주의해라. Component-scanning을 위한 기본 매칭룰은 패키지안에 있는 클래스들의 모든 스프링 stereotype 어노테이션들을 순환적으로 탐색할것이다.(다수의 패키지들은 콤마(,)로 분리된 리스트에서 제공받을 수 있다.) 그러므로 PetClinic 샘플 어플리케이션을 위한 다양한 컨트롤러 실행들은 전부 @Controller(스프링의   고유 stereotype들중의 한가지) 어노테이션 처리된 것들이다. 여기에 예가 있다.

 

@Controller
public class ClinicController {
 
  
private final Clinic clinic
;
 
   @Autowired
  
public
ClinicController(Clinic clinic) {
              
this.clinic
= clinic;
   }
 ...

 

 만약 자동 탐색된 components들이 XML에 정의되어 있다면 그것들은 스프링 컨테이너에 등록된다. 위에서 서술된것처럼 이러한 객체들은 어노테이션 주도의 autowiring을 사용한다.

 component탐색기의 매칭룰은 타입,어노테이션,AspectJ,이름패턴을 위한 정규식에 기반을 둔 components를 포함하거나 배제하는 용도로 쓰이는 필터들로 커스터마이즈될 수 있다. 기본 stereotypes는 비활성화될 수 있다. 예를 들면, 테스트 환경설정은 기본 stereotypes를 무시할 수도 있고 그 대신 Stub로 시작하는 이름을 가지거나 @Mock 어노테이션을 포함하는 모든 클래스들을 자동검색한다.

 

<context:component-scan base-package="example" use-default-filters="false">
   <context:include-filter type="aspectj" expression="example..Stub*"/>
   <context:include-filter type="annotation" expression="example.Mock"/>
</context:component-scan>

 

 게다가 타입 일치 규정들은 제외필터들과 같이 관리될 수 있다. 예를 들면, @Repository 어노테이션을 제외한 기본필터들에 의지하기 위해 exclude-filter를 추가하라.

 

<context:component-scan base-package="example">

<context:exclude-filter

type="annotation" expression="org.springframework.stereotype.Repository"/>

</context:component-scan>

 

커스텀 타입들을 등록시키는 여러가지 방법들로 component scanning을 확장시키는 것이 가능하다. Stereotype 어노테이션은 가장 간단한 선택사항이고 이로 인해 stereotype의 개념은 확장성이 있다. 이전에 언급했듯이 @Component@Repository,@Service,@Controller 어노테이션들이 논리적으로 확장시키는 제네릭 stereotype 지시어이다. 마침 @Component는 메타 어노테이션으로서 제공된다. (. 다른 어노테이션에 선언된 어노테이션) 그리고 @Component 메타 어노테이션을 가지고 있는 모든 커스텀 어노테이션은 탐색기의 기본 매칭룰에 의해 자동적으로 탐색될것이다.

@PostConstruct@PreDestroy 라이프 사이클 어노테이션 부분에서 서술된 가상의 백그라운드 작업을 상기하라. 아마도 어플리케이션은 그와 같이 많은 백그라운드 작업을 가지고 있고 이러한 작업 인스턴스들은 스프링 컨텍스트에 등록되기 위해 전형적으로 XML 빈 정의를 필요로 하고 제때에 호출되는 그들의 라이프 사이클 메소드들을 가지고 있다.

Component scanning으로 인해 더 이상 명시적인 XML 빈 정의는 필요하지 않다. 만약 모든 백그라운드 작업이 같은 인터페이스를 실행하거나 명명규칙을 따른다면 include-filters가 사용될 수 있다. 그러나 더 단순한 접근은 이러한 작업 객체들을 위한 어노테이션을 생성하고 @Component 메타 어노테이션을 제공하는 것이다.

 

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component

public @interface
BackgroundTask {
   String value()
default ""
;
}

 

그 다음에 모든 백그라운드 작업의 클래스 정의에서 커스텀 stereotype 어노테이션을 제공하라.

 

@BackgroundTask
public class FilePoller {
 
   @PostConstruct
  
public void
startPolling() {
              ...
   }
 
   @PreDestroy
  
public void
stopPolling() {
              ...
   }
   ...
}

 

 

그 대신 제네릭 @Component 어노테이션이 제공되어 왔지만 커스텀 어노테이션 기법이 의미심장한 특정 도메인 이름들을 사용할 기회를 제공한다. 이런 특정 도메인 어노테이션들은 이러한 작업들의 할동을 감시하는 충고를 추가하기 위한 모든 백그라운드 작업들을 확인하기 위해 AspectJ pointcut식을 사용하는 것과 같은 추가적인 기회를 제공한다.

 기본적으로 component가 탐지될 때 스프링은 자격이 없는 클래스 이름을 사용하여 자동적으로 빈 이름을 생성한다. 이전의 예에서 생성된 빈 이름은 filePoller였다. 그러나 스 프링의 stereotype 어노테이션들(@Component, @Repository, @Service, or @Controller)중의 한가지로 어노테이션 처리된 모든 클래스나 메타 어노테이션으로서 @Component를 사용하여 어노테이션 처리된 다른 모든 어노테이션들을 위해 value속성은 stereotype 어노테이션에 적합하게 기입될 수 있고, 인스턴스는 빈 이름으로서 그 값을 가지고 있는 컨텍스트에 등록될 것이다. 다음의 예에서 보듯이 기본으로 생성된 이름인 simpleJdbcClinic 대신 petClinic이다.

 

@Service("petClinic")
public class SimpleJdbcClinic {
   ...
}

 

마찬가지로 FilePoller의 수정된 버전을 위해 생성된 빈 이름은 filePoller 대신에 poller이다.

 

@BackgroundTask("poller")
 public class FilePoller {
   ...
}

 

모든 스프링에 의해 관리되는 객체들이 기본적으로 싱글톤 인스턴스들로 취급되는 동안, 객체에 적합한 교대의 scope을 구체화하는 것은 때때로 필요하다. 예를 들면, tier에서 스프링에 의해 관리되는 객체는 request 또는 session의 범위안에 있게 된다. 커스텀 scope이 어플리케이션 컨텍스트에 등록될 수 있도록 하기 위해서 현재 스프링 버전 2.0 scope기법은 확장성이 있다. XML환경설정 안에서 scope의 이름과 scope속성을 포함하는 것은 간단하다.

 

<bean id="shoppingCart" class="example.ShoppingCart" scope="session">
   ...
</bean>

 

스프링 2.5 @Scope 어노테이션을 제공함으로써 탐지된 component를 위한 동일한 기능이 완성되었다.

 

@Component
@Scope("session")

public class
ShoppingCart {
   ...
}

 

여기서 마지막 주제는 component-scanning을 사용할때 qualifier어노테이션의 간소화이다. 이전 설명에서 아래의 객체는 커스텀 qualifier 어노테이션과 함께 autowiring의 예로서 사용되었다.

 

@VetSpecialty("dentistry")
private Clinic dentistryClinic;

 

똑같은 예는 의존성을 위해 의도적으로 대상이 되는 빈 정의의 XML내에 있는 qualifier 엘리먼트의 사용을 특색으로 삼았다. Component-scanning을 사용할 때 XML 메타 데이터는 필요하지 않다. 대신 커스텀 qualifier 대상 클래스 정의에서 타입 레벨 어노테이션으로서 포함될 수도 있다. 의존성이 나타나면서 탐지된 @Repository 인스턴스를 가지고 있는 예이다.

 

@Repository
@VetSpecialty("dentistry")

public class DentistryClinic implements
Clinic {
   ...
}

 

마지막으로 속성들을 가지고 있는 커스텀 qualifier 어노테이션들을 언급한 이전의 예를 위해 의존 대상과 동등한 가치를 지닌 비XML은 아래와 같다.

 

@Repository
@SpecializedClinic(species="dog", breed="poodle")

public class PoodleClinic implements
Clinic {
   ...
}



'I.lib() > I.lib(Spring)' 카테고리의 다른 글

Eclipse 3.6 Helios에 STS 설치하기  (1) 2011.04.26
CronTrigger (잡 스케쥴링)  (1) 2010.04.08
Spring 트랜잭션 격리 수준, 전달 행위의 값  (0) 2010.04.02
AOP 용어  (0) 2010.03.26
Spring ppt 모음  (1) 2010.03.24
.
:
Posted by .07274.
.. .. ..


* 트랜잭션 격리 수준

 격리수준 설명 
 ISOLATION_DEFAULT PlatformTransactionManager의 기본 격리수준으로 대부분의 데이터베이스에 ISOLATION_READ_COMMITTED가 적용된다. 
 ISOLATION_READ_UNCOMMITTED 가장 낮은 수준의 격리수준이다. 즉, 이 트랜잭션이 수정한 데이터는 심지어 커밋하기도 전에 다른 트랜잭션이 볼 수 있기 때문에 실제로 이것을 격리수준이라고 부를 수는 없다. 또한 이 트랜잭션은 다른 트랜잭션이 커밋을 하기 전에 변경내용ㅇ을 볼수있다. 
 ISOLATION_READ_COMMITED 대부분의 데이터베이스에서 지원하는 기본 격리수준으로 트랜잭션이 완료하기 전에는 데이터에 대한 수정사항을 다른 트랜잭션들이 볼 수 없도록 명시한다. 하지만 다른 트랜잭션이 커밋한 입력/ 수정 데이터를 조회 할수이 ㅆ다. 이것은 다른 트랜잭션이 수정한 데이터를 볼 수 있기 때문에 트랜잭션의 시점에 따라 다른 데이터를 볼 수 있다는 것을 의미한다. 
 ISOLATION_REPEATABLE_READ ISOLATION_READ_COMMITTED보다 엄격한 격리수준으로 트랜잭션 내에서 데이터를 조회하는 경우 다른 트랜잭션이 조회 대상 데이터를 변경하였다고 하더라도 적어도 처음과 동일한 데이터를 조회할 수 있도록 ㅈ보장해준다. 그러나 다른 트랜잭션이 새로운 데이터를 입력하였다면 새롭게 입력된 데이터를 조회할 수 있게 된다. 
 ISOLATION_SERIALZBLE 가장 비용이 많이 들고 신뢰도가 높은 격리수준이다. 모든 트랜잭션은 한번에 하나씩 순차적으로 실행된다. 


* 전달 행위의 값

 전달행위 설명 
 PROPAGATION_REQUIRED 활성화된 트랜잭션이 존재한다면 스프링은 이 트랜잭션을 사용하고 그렇지 않다면 새로운 트랜잭션을 시작한다.  
 PROPAGATION_ SUPPORTS  활성화된 트랜잭션이 존재한다면 스프링은 이 트랜잭션을 사용하지만 활성화된 트랜잭션이 없다면 새로운 트랜잭션을 시작하지 않는다.
 PROPAGATION_MANDATORY  활성화된 트랜잭션이 존재한다면 스프링은 이 트랜잭션을 사용하지만 활성화된 트랜잭션이 없다면 스프링은 예외를 던진다.
 PROPAGATION_REQUIRES_NEW 스프링은 항상 새로운 트랜잭션을 시작한다. 만약 활성화된 트랜잭션이 이미 존재한다면 이 트랜잭션은 잠시 중지된다.
 PROPAGATION_ NOT_SUPPORTED  스프링은 활성화된 트랜잭션 내에서 코드를 실행하지 않는다. 코드는 항상 트랜잭션이 아닌 상태에서 실행되며 기존에 존재하는 트랜잭션이 있다면 모두 잠시 중지시킨다.
  PROPAGATION_NEVER 활성화된 트랜잭션이 존재해도 항상 트랜잭션 없이 코드를 실행한다. 만약 활성화된 트랜잭션이 존재한다면 예외를 던진다.
  PROPAGATION_NESTED  활성화된 트랜잭션이 존재 하면 중텁된 트랜잭션 내에서 실행된다. 만약 활성화된 트랜잭션이 없다면 코드는 TransactionDefinition.PROPAGATION_REQUIRED가 설정된 것처럼 실행된다.

'I.lib() > I.lib(Spring)' 카테고리의 다른 글

CronTrigger (잡 스케쥴링)  (1) 2010.04.08
Spring Annotation (스프링 어노테이션)  (1) 2010.04.06
AOP 용어  (0) 2010.03.26
Spring ppt 모음  (1) 2010.03.24
Spring Tutorial  (0) 2010.03.24
.
:
Posted by .07274.
.. .. ..


SOAP 란 ?


 SOAP은 웹상의 객체들을 액세스하기 위한 마이크로소프트의 프로토콜이다.

이 프로토콜은 HTTP를 사용하여 인터넷에 텍스트 명령어를 보내기 위해 XML 구문을 쓴다. 
 SOAP은 COM, DCOM, 인터넷 익스플로러, 마이크로소프트의 자바 이행 등 내에서 지원된다.


왜 SOAP 인가?


 인터넷을 통해 기업과 기업, 기업과 고객의 장벽이 없어진 상황에서 서로 다른 인프라를 바탕으로 하는 컴포넌트를 연결하는 방법이 절실한 현실에서 JAVA, CORBA, COM 등의 주요 컴포넌트 기술은 독자적인 인프라와 기술을 사용하므로 상호 운용성이 크게 떨어지게 마련이다.

 즉, 현재의 주 컴포넌트 기술로 일컬어지는 JAVA, CORBA, COM 등은 목적은 비슷하지만 목적을 구현하는 방법은 매우 다르므로 호환성을 기대하기 어렵다.

 예를 들어보자.

 상호 운용에 필요한 하나의 요소는 컴포넌트를 액세스하기 위한 타입(클래스, 인터페이스)이다.

CORBA와 COM은 IDL에 기반한다는 공통점이 있지만, IDL 문법에 차이가 많으며 IDL이 생성한 컴포넌트의 타입 정보를 제공하는 방법 역시 공통점을 찾기 어렵다. 반면 JAVA는 IDL을 사용하지 않고 언어 자체가 갖는 타입 정보를 이용한다. 또한, 상호 운용에서 중요한 것은 통신 메커니즘이지만 CORBA는 IIOP(Internet Inter-ORB Protocol)를, 자바는 RMI(Remote Method Invocation)를, COM은 DEC RPC(Remote Procedure Call)을 사용한다. 그리고 이들 통신 메커니즘 역시 공통점이 없다.

이들 컴포넌트 기술들은 고유의 장단점을 갖고 있으며, 어는 것이 다른 것에 대해 우월하다거나 뒤진다고 말할 수 없다. 또한 수년에 걸쳐 많은 자원과 시간을 투자한 고유의 추종자들을 거느리고 있으므로 JAVA, CORBA, COM 중 어느 하나가 사라질 것으로 예견하는 이는 아무도 없을 것이다. 더욱 문제되는 것은 이들 중 어느 한 기술이 인터넷을 지배하고 있거나, 지배할 가능성 역시 거의 없다는 것이다. 이것이 현재의 컴포넌트 기술들이 갖는 상호 운용성의 큰 문제가 되는 것이다.



결국 해결책은 SOAP ?


SOAP은 XML과 HTTP를 사용해 플랫폼에 독립적으로 서비스 혹은 분산 객체를 액세스하는 방법을 정의한다.


HTTP는 인터넷 표준이며 누구나 어떠한 플랫폼에서도 사용할 수 있는 프로토콜이다.

그 어떤 개인이나 기업도 HTTP를 인정한다. XML은 HTTP보다 상대적으로 늦게 나온 기술이지만 최근 들어 널리 사용되며 업계 표준으로 자리잡고 있다. 또한 HTTP와 XML은 공통적으로 텍스트에 기반하고 있으므로 이들을 처리하는 소요 비용(프로세싱 시간, 메모리 등)은 상대적으로 매우 적다. 텍스트 문자열을 제어하고 TCP/IP에 접근할 수 잇는 어떠한 응용 프로그램도 HTTP를 통해 XML데이터를 전송하거나 수신할 수 있다는 것이다. 이러한 손쉬운 사용성은 이들 두 기술이 빠르게 IT 환경에 적응하는 발판이 됐다.

 SOAP은 이런 XML과 HTTP를 사용함으로써 이들이 갖는 장점을 모두 포함하면서 컴포넌트의 상호 운용성을 높일 수 있는 것이다.


SOAP의 장점


  • 독립성

     
 SOAP은 XML과 HTTP를 이용해 어떤 인터페이스의 메쏘드를 호출할 것이며, 이 메쏘드에 대한 매개변수를 알리는 역할만 담당한다. 따라서 실제 컴포넌트를 생성하거나 컴포넌트에 대한 직접적인 호출에 관여하지 않는다.

 즉, SOAP은 컴포넌트를 활성화하는 방법이나 호출 방법에 대해 전혀 관여하지 않으며, 이에 대한 상세한 것은 HTTP Request를 수신하는 수신자에게 위임하고 있다. 따라서 객체 지향 기술이나 컴포넌트 기술을 사용하지 않는 애플리케이션일지라도 SOAP을 통해 객체 서비스를 제공하거나 제공받을 수 있다.

 결론적으로 말해, SOAP은 JAVA, CORBA, COM 등의 분산 객체 기술에 구애받지 않는 프로토콜이며 심지어 이들 분산 객체 기술을 전혀 사용하지 않는 애플리케이션도 SOAP을 통해 원격 프로시져 호출이나 데이터 전송을 수행할 수 있다. SOAP이 원격 객체의 구현에 대해 언급하고 있지 않으므로, 원격 객체는 어떤 프로그래밍 언어로도 구현할 수 있다.
 
  • 인터넷 적용성

 SOAP은 transport로서 HTTP를 사용한다.
 HTTP를 사용함으로써 얻을 수 있는 장점은 인터넷에서 널리 사용할 수 있다는 점이다.
 실제로 SOAP은 인터넷에서 원격 객체를 액세스하기 위해 고안된 프로토콜이다.
 그렇다면 기존 객체 지향 기술은 인터넷에서 문제가 있었던 것인가 살펴보도록 하자.

 JAVA, CORBA, COM 등이 사용하는 transport는 고유의 transport로서 RMI, IIOP, DCOM을 사용하지만, 이들 프로토콜은 TCP/IP 포트를 동적 할당하는 메커니즘을 사용하고 있다. 이것 때문에 이들 프로토콜이 방화벽을 통과하는데 문제점이 드러난다.

 예를 들어 DCOM을 인터넷에서 사용하려면 방화벽에 일정 영역의 TCP/IP 포트를 열어 놓아야 하는데, 이것은 방화벽을 사용하지 않는 것과 다름없게 만들어 버린다.
 반면 대부분의 기업 네트워크는 자사의 웹 사이트를 위해 HTTP가 사용하는 포트를 열어 놓고 있다.

 SOAP은 HTTP를 사용하므로 아무런 문제 없이 방화벽을 통과할 수 있다. 또한 대부분의 방화벽 제품은 HTTP 헤더의 내용을 읽어 필터링을 수행할 수 있으므로 특정 인터페이스의 특정 메쏘드를 호출하는 SOAP 메시지만을 통과시키도록 설정할 수도 있다.

 SOAP은 HTTP를 통해 인터넷에 분산된 객체들에 접근할 수 있으며 방화벽이나 HTTPS 등의 인터넷 보안 기술을 그대로 적용받을 수 있는 것이다.
 
  •  표준

 SOAP 탄생의 주역은 마이크로소프트와 IBM이다.

 초기 마이크로소프트 제품의 대부분이 자사의 고유한 기술을 사용했던 것과 반대로 최근 마이크로소프트의 제품들은 업계 표준이나 인터넷 표준을 준수하기 시작했다. SOAP 역시 인터넷 표준으로서 XML과 HTTP를 채택하고 있으며 SOAP 자체 역시 W3C에 표준으로서 제출된 상태이다. 2001년 초 현재 W3C에 제출됐고 검토되고 있는 SOAP의 최신 버전은 스펙 1.1이다.


 SOAP이 W3C로부터 공식 표준으로 인정받을 것은 확실시 되고 있으며 플랫폼과 운영체제, 애플리케이션 그리고 프로그래밍 언어를 뛰어넘는 분산 객체 프로토콜로 자리잡을 가능성 역시 매우 높다. 


출처 [http://www.saga21.net/417]
글쓴이 [사가]

.
:
Posted by .07274.
2010. 3. 29. 14:19

자바 리플랙션 (Java Reflection) I.lib()/I.lib(Java)2010. 3. 29. 14:19

.. .. ..
일상에서의 리플렉션(reflection)이란 거울 속에 비친 자신의 모습입니다. 프로그래밍 세상에서의 리플렉션은 프로그램이 자신의 모습을 보고 심지어 수정하기 까지 하는 것을 말합니다. Java reflection API는 바로 그런 기능을 언어의 기본 요소인 클래스, 필드, 메소드를 들여다 볼 수 있는 평범한 Java API를 통해 제공합니다. 리플렉션을 이해하는 것은 여러분이 자주 사용하는 툴을 이해하는데 도움이 됩니다. Eclipse가 어떻게 자동완성으로 메소드 이름을 만들어 줄까? Tomcat은 web.xml파일에 있는 클래스 이름을 가지고 웹의 요청을 처리할 서블릿을 실행하는 걸까? Spring은 어떻게 마술 같은 dependency injection을 하는 것일까? 여러분의 프로그램에서도 리플렉션을 사용하여 보다 동적이고 유연한 코드를 작성하실 수 있습니다. 리플렉션을 사용하면 이전에 본적 없는 클래스들을 매우 멋지게 처리할 수 있습니다.

클래스 만들기

이미 말했듯이 리플렉션의 기본 아이디어는 프로그램이 동작하는 내부에 집어 넣을 API를 제공하는 것입니다. Java에서 가장 기본이 되는 사상이 바로 클래스기 때문에(클래스 없이 자바 프로그램을 만들어 보세요) Class 클래스부터 살펴보는 것이 좋겠습니다. 이것의 객체는 Class 타입일 것입니다. 일단 Class객체를 가지게 되면 그것으로부터 클래스에 관련된 모든 정보를 뽑아낼 수 있습니다. 클래스의 이름, 그것이 public 인지 abstract 인지 final 인지 그리고 심지어 상위 클래스까지 말이죠.

이 정도면 이론은 충분합니다. 자, 이제 리플렉션 현미경을 가지고 아래에 있는 매우 간단한 Employee 클래스를 살펴봅시다.
package com.russolsen.reflect;

public class Employee{
   public String _firstName;
   public String _lastName;
   private int _salary;

      public Employee()   {
      this( "John", "Smith", 50000);
   }
 
   public Employee(String fn, String ln, int salary)   {
      _firstName = fn;
      _lastName = ln;
      _salary = salary;
   }
   
   public int getSalary()   {
      return _salary;
   }
   
   public void setSalary(int salary)   {
      _salary = salary;
   }
   
   public String toString()    {
      return "Employee: " + _firstName +  " "
             + _lastName + " " + _salary;
   }

}
Class 객체를 만드는 가장 쉬운 방법은 해당 클래스 객체의 getClass 메소드를 호출하는 것입니다. 아래에 있는 코드는 Employee 객체를 만들고 그것의 Class 객체를 만들어서 클래스에 대한 다양한 정보들을 출력합니다.
package com.russolsen.reflect;

import java.lang.reflect.Modifier;

public class GetClassExample{
   public static void main(String[] args)   {
 
      Employee employee = new Employee();
      Class klass = employee.getClass();
      
      System.out.println( "Class name: " + klass.getName());
      System.out.println( "Class super class: " + klass.getSuperclass());
      
      int mods = klass.getModifiers();
      System.out.println( "Class is public: " + Modifier.isPublic(mods));
      System.out.println( "Class is final: " +  Modifier.isFinal(mods));
      System.out.println( "Class is abstract: " + Modifier.isAbstract(mods)); 
   }

}
코드를 실행하면 다음과 같은 결과를 확인할 수 있습니다.
Class name: com.russolsen.reflect.Employee
Class super class: class java.lang.Object
Class is public: true
Class is final: false
Class is abstract: false
예제에서 보이듯이 클래스의 이름과 상위 클래스를 알아내는 것은 다른 접근 메소드들(Getters or Accessors)을 호출하는 것처럼 쉬운 일입니다. 만약 해당 클래스가 public 인지 abstract 인지 final 인지 알고 싶다면 약간 복잡해 집니다. 이 모든 정보가 getModifires에 의해 하나의 int 값으로 패키징되어 넘어오기 옵니다. 다행히 Java는 Modifier 클래스를 통해 getModifiers에서 넘어온 숫자를 가지고 여러 일을 할 수 있는 static 메소드들을 제공해 줍니다.

객체에 getClass를 호출하는 것 만이 Class 객체를 얻을 수 있는 유일한 방법은 아닙니다. 클래스 이름을 사용하여 직접 얻을 수도 있습니다.
Class klass = Employee.class;
 
세 번째 방법은 좀 더 흥미로운 방법입니다. 문자열을 통해서 Class 객체를 생성할 수 있습니다. 물론 그 문자열이 클래스 이름을 포함하고 있을 때 말이죠. 다음과 같이 Class 클래스에 있는 forName 을 호출하여 얻을 수 있습니다.
      Class klass = Class.forName("com.russolsen.reflect.Employee");
      
      System.out.println( "Class name: " + klass.getName());
      System.out.println( "Class super class: " + klass.getSuperclass());
      
      // Print out the rest...
forName을 사용할 때 한 가지 주의할 것은 클래스 이름 앞에 완전한 패키지 경로를 붙여줘야 한다는 것입니다. 평범하고 늙은 “Employee” 말고 “com.russolsen.reflect.Employee" 여야만 합니다. forName을 통해 리플렉션 API의 기본적인 강력함(그리고 멋진 것)을 살펴봤습니다. 클래스 이름을 포함한 문자열로 시작할 수도 있고 class로 끝낼 수도 있습니다.

바로 인스턴스 만들기

class 객체를 가져오고 그것에 관한 정보를 찾는 것은 그것 자체로도 흥미롭고 유용합니다. 하지만 진짜 재미있는 것은 리플렉션을 사용하여 무언가를 실제 해보는 것입니다. Class 객체를 가지고 할 수 있는 가장 눈에 띄는 작업은 그 클래스의 새로운 객체를 만드는 것입니다. newInstance 메소드를 사용하여 간단하게 만들 수 있습니다. 실제 사용하는 것을 보여 주기 위하여 아래에 있는 간단한 프로그램은 커맨드 라인 인자(command line argument)로 Class 객체를 만들고 그 클래스 타입의 객체를 만드는 프로그램을 보여줍니다.
package com.russolsen.reflect;

public class NewInstanceExample
{
   public static void main(String[] args)
      throws ClassNotFoundException,
      InstantiationException, IllegalAccessException
   {

      Class klass = Class.forName(args[0]);
      Object theNewObject = klass.newInstance();
      System.out.println("Just made: " + theNewObject);
   }
}
위 코드를 "com.russolsen.reflect.Employee" 인자와 함께 실행하면 새로운 Employee 객체를 만들게 됩니다.
Just made: Employee: John Smith 50000

Run it again, but this time feed it "java.util.Date" and you will get:

Just made: Tue Feb 27 20:25:20 EST 2007
간단한 코드 몇 줄로 얼마나 많은 유연성을 얻게 되었는지 생각해보세요. 위에 있는 프로그램은 실제 Employee 나 Date 클래스에 관해 아는 것이 하나도 없지만 각각의 새로운 객체들을 만들 수 있습니다. 이것이야 말로 Java 프로그래밍을 하는 또 다른 방법입니다.

인자 없는 생성자 너머에

Class.newInstance 메소드를 호출하는 것은 인자 없이 new를 사용하는 것과 동일합니다. 그러나 만약 인자가 없는 생성자 즉 default 생성자가 없는 클래스에 newInstance를 호출하면 어떻게 될까요? 좋을 일 없습니다. 별로 맘에 안 드는 InstantiationException을 받게 됩니다.

좋은 소식이 있습니다. 생성자 인자를 필요로 하는 클래스의 객체를 동적으로 만들 수 있습니다. 하지만 약간 더 힘든 작업을 해야 합니다. 그건 바로 클래스에서 해당 생성자를 찾고 적당한 인자를 사용하여 그것을 호출하는 일입니다. 적당한 생성자를 찾는 일은 여러분이 찾고자 하는 생성자에 대한 정보를 가지고 getConstrucor 메소드를 사용하면 됩니다. 그럼 Constuctor 객체를 얻게 되고 그것을 사용하여 새로운 객체를 만들 수 있습니다.
Let's see how this all works in code:
      Class klass = Class.forName("com.russolsen.reflect.Employee");

      Class[] paramTypes = {
            String.class, 
            String.class, 
            Integer.TYPE };
      
      Constructor cons = klass.getConstructor(paramTypes);
      
      System.out.println( "Found the constructor: " + cons);

      
      Object[] args = { 
            "Fred", 
            "Fintstone", 
            new Integer(90000) };
      
      Object theObject = cons.newInstance(args);
      System.out.println( "New object: " + theObject);
생성자들 사이의 차이점은 오직 그것들이 가지고 있는 매개 변수들입니다. 따라서 getConstructor 메소드에 찾고자 하는 생성자에 들어갈 매개변수 각각의 Class들 객체의 배열을 넘겨줍니다. 위에 있는 예제에서는 두 개의 String 그리고 하나의 int를 받는 생성자를 찾게 됩니다. Constructor 객체를 얻은 뒤 새로운 객체를 생성하는 일은 간단합니다. 실제 인자로 들어갈 객체의 배열을 newInstance 메소드를 호출하면서 넘겨주면 됩니다.

geConstructor에는 조그만 지뢰가 하나 있습니다. 파라미터의 타입으로 생성자를 식별하여 원하는 것을 찾을 때 primitive 인자와 그것의 wrapper 클래스를 잘 구별해야 합니다. 생성자가 인자로 primitive 타입인 int를 받는 것인가 아니면 그것의 삼촌 격인 java.lang.Integer 클래스의 객체를 받는 건가요? 만약 java.lang.integer 같은 wrapper 타입의 객체를 받는 생성자라면 Integer.class처럼 wrapper 클래스를 사용하면 됩니다. primitive 타입인 int를 사용하는 생성자라면 Integer.TYPE을 사용합니다. TYPE은 primitive을 위해 마련한 것입니다. 모든 wrapper 클래들은 static 타입인 TYPE 필드를 가지고 있고 이것을 사용하여 primitive 타입이라는 것을 알려줄 수 있습니다

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

클래스를 좀 더 자세히 살펴보기

첫 번째 예제에서 봤듯이 Class 객체는 그것의 이름이나 상위 클래스 같은 정보를 제공합니다. 이 이름을 사용하여 좀 더 자세히 rank 와 시리얼 넘버(serial number) 차원의 정보까지 알 수 있습니다. 예를 들어 getMethods 메소드를 사용하여 클래스가 가진 모든 public 메소드를 찾을 수 있습니다.
      Class klass = Class.forName("com.russolsen.reflect.Employee");
           
      Method[] methods = klass.getMethods();
      
      for(Method m : methods )   {
         System.out.println( "Found a method: " + m );
      }
getMethods 는 클래스가 가지고 있는 public 메소드 각각에 해당하는 Method 객체의 배열을 반환합니다.
Found a method: public java.lang.String com.russolsen.reflect.Employee.toString()
Found a method: public int com.russolsen.reflect.Employee.getSalary()
Found a method: public void com.russolsen.reflect.Employee.setSalary(int)
Found a method: public native int java.lang.Object.hashCode()
Found a method: public final native java.lang.Class java.lang.Object.getClass()
Found a method: public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
Found a method: public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
Found a method: public final void java.lang.Object.wait() throws java.lang.InterruptedException
Found a method: public boolean java.lang.Object.equals(java.lang.Object)
Found a method: public java.lang.String java.lang.Object.toString()
Found a method: public final native void java.lang.Object.notify()
Found a method: public final native void java.lang.Object.notifyAll()
getMethods는 클래스의 사용자(client) 입장이기 때문에, 배열에는 자신이 가지고 있는 모든 public 메소드 (Object 까지 달하는 모든 상속 계층의 상위 클래스들에 있는 public 메소드까지 포함하여)를 배열에 담아 줍니다.

만약 하나의 메소드에만 관심이 있다면, getMethod(단수 형태 입니다.)를 사용할 수 있습니다. getConstructor와 비슷하게 동작하지만 파라미터 타입들 뿐만 아니라 메소드의 이름도 넘겨 줘야 합니다. 아래에 있는 코드는 하나의 int 파라미터를 가지는 setSalary 라는 메소드를 찾습니다.
      Class klass = Class.forName("com.russolsen.reflect.Employee");
      Class[] paramTypes = {Integer.TYPE };
      Method setSalaryMethod = 
         klass.getMethod("setSalary", paramTypes);
           
      System.out.println( "Found method: " + setSalaryMethod);
리플렉션을 사용하여 메소드를 호출하는 것은 constuctor를 호출하는 것과 매우 유사합니다. 앞서 살펴봤던 Method 객체만 있으면 되고 메소드에 인자로 넘겨 줄 배열과 메소드를 호출할 객체가 필요합니다. 아래에 있는 코드는 우리 직원에게 월급을 올려주기 위해서 Employee 객체에 있는 setSalary 메소드를 호출합니다.
      Class klass = Class.forName("com.russolsen.reflect.Employee");

      Class[] paramTypes = {Integer.TYPE };
      Method setSalaryMethod = 
         klass.getMethod("setSalary", paramTypes);
      
      Object theObject = klass.newInstance();
      Object[] parameters = { new Integer(90000) };
      
      setSalaryMethod.invoke(theObject, parameters);
그냥 theObject.setSalary(9000)를 호출하지 않고 왜 그렇게 귀찮게 했을까요? 위에 있는 코드를 자세히 살펴보시길 바랍니다. 코드의 첫 번째 줄을 빼면 위에 있는 프로그램은 완전히 일반적입니다. 어떤 클래스의 어떤 객체든 상관없이 setSalary 메소드를 호출할 것입니다. 약간만 수정하면 어떤 클래스의 어떤 객체든 거기에 있는 모든 메소드를 호출하는 코드로 사용할 수 있습니다.

필드 가지고 놀기

리플렉션을 사용하여 메소드를 호출하는 데에서 그치지 않습니다. 필드에 대한 모든 권한 역시 가지고 있습니다. getMethods 처럼 getFields는 해당 클래스 또는 그것의 상위 클래스에 있는 모든 public 필드 각각에 대한 Fileld 객체의 배열을 반환합니다.
      Class klass = Class.forName("com.russolsen.reflect.Employee");
      System.out.println( "Class name: " + klass.getName());
      Field[] fields = klass.getFields();
      for(Field f : fields ){
         System.out.println( "Found field: " + f);
      }
Employee 가 두 개의 public 필드를 가지고 있기 때문에 두 개의 멤버를 가진 배열을 얻게 됩니다. 
Class name: com.russolsen.reflect.Employee
Found field: public java.lang.String com.russolsen.reflect.Employee._firstName
Found field: public java.lang.String com.russolsen.reflect.Employee._lastName
getField메소드를 사용하여 특정 필드 하나만 가져올 수도 있습니다.
      Field field = klass.getField("_firstName");
      System.out.println("Found field: " + field);
Field 객체를 가지고 get 메소드를 호출하면 필드가 가진 값을 가져올 수 있고 set을 사용하여 값을 설정할 수 있습니다.
      Object theObject = new Employee("Tom", "Smith", 25);
      
      Class klass = Class.forName("com.russolsen.reflect.Employee");
      
      Field field = klass.getField("_firstName");
      
      Object oldValue = field.get(theObject);
      System.out.println( "Old first name is: " + oldValue);
      
      field.set( theObject, "Harry");
      Object newValue = field.get(theObject);
      System.out.println( "New first name is: " + newValue);
위에 있는 코드를 실행하고 _firstName 필드가 변하는 것을 주의 깊게 살펴보시기 바랍니다.
Old first name is: Tom
New first name is: Harry
규칙 깨기

Java의 가장 신성한 규칙 중 하나를 깨는 방법을 얘기하지 않고서는 리플렉션을 마무리할 수 없습니다. 여러분 모두 잘 알다시피 해당 클래스 밖에서는 private 메소드를 호출 할 수 없습니다. 그렇죠? 아마 평범한 기술을 사용하는데 그친다면 하지 못할 것입니다. 하지만 리플렉션을 사용하면 거의 모든 걸 할 수 있습니다.

private 메소드를 호출하기 위해서 가장 먼저 해야 할 일은 호출하고 싶어 하는 메소드를 나타내는Method객체를 얻는 것입니다. getMethod로는 얻을 수 없습니다. 그건 오직 public 메소드만 반환합니다. private(또는 protected)메소드를 가져오는 방법은 getDeclaredMethod를 사용하는 것입니다. getMethod는 해당 클래스의 사용자 관점(client’s view)에서 public 메소드만 가져오지만, getDeclaredMethod는 클래스에 선언한 모든 메소드를 반환합니다. 아래에 있는 예제에서 java.util.ArrayList 클래스에 있는 private 메소드인 removeRange 를 가져옵니다.
      ArrayList list = new ArrayList();
      list.add("Larry");
      list.add("Moe");
      list.add("Curley");

      System.out.println("The list is: " + list);

      Class klass = list.getClass();

      Class[] paramTypes = { Integer.TYPE, Integer.TYPE };
      Method m = klass.getDeclaredMethod("removeRange", paramTypes);

      Object[] arguments = { new Integer(0), new Integer(2) };
      m.setAccessible(true);
      m.invoke(list, arguments);
      System.out.println("The new list is: " + list);
private 메소드를 받은 뒤에 간단히 setAccessable 안전장치를 제거하고 호출하면 됩니다.
The list is: [Larry, Moe, Curley]
The new list is: [Curley]
removeRange 메소드는 리스트에서 주어진 범위의 아이템을 제거하는 것처럼 보입니다. 이것은 매우 강력한 마술입니다. java.util 에 있는 클래스에 접근하여 그 안에 있는 private 메소드를 호출할 수 있습니다. 이것을 사용하여 코드의 의도를 우회하여 private 메소드를 호출하는 취미를 즐기실 건가요? 아니죠! 그러나 저런 것들이 약간은 유용할 때가 있습니다.

결론

리플렉션을 사용하여 Java의 규칙을 무시하는 것처럼 보이는 것들을 하는 프로그램을 작성할 수 있습니다. 일반적으로는 알 수 없는 클래스에 관한 정보를 모두 알아내는 코드를 작성할 수 있습니다. 그리고 동적으로 알아낸 정보에 어떤 행위를 할 수도 있습니다. 즉 새로운 객체를 만들고 메소드를 호출하고 필드에 값을 설정하거나 가져올 수 있습니다. 극단적인 경우에서는 클래스의 private 멤버들에 접근할 수 있습니다. 점점 복잡해져가는 Java 개발 툴의 동작을 이해하기 위해서는 리플렉션에 대한 이해가 필요합니다. 또한 “평범한” Java 프로그램이 할 수 있는 것 이상의 프로그램을 작성해야 할 때도 필요합니다.


제공 : 한빛 네트워크
저자 : Russ Olsen
역자 : 백기선
원문 : Reflections on Java Reflection

'I.lib() > I.lib(Java)' 카테고리의 다른 글

Heapdump 파일 생성 이유  (0) 2010.05.19
JNDI 란?  (1) 2010.04.08
자바의 abstract와 인터페이스(Interface)  (0) 2010.03.24
Javap 란? (자바 역어셈블러)  (1) 2010.03.24
POJO (Plain Old Java Object) 란?  (0) 2010.03.23
.
:
Posted by .07274.
2010. 3. 26. 10:30

AOP 용어 I.lib()/I.lib(Spring)2010. 3. 26. 10:30

.. .. ..

'I.lib() > I.lib(Spring)' 카테고리의 다른 글

Spring Annotation (스프링 어노테이션)  (1) 2010.04.06
Spring 트랜잭션 격리 수준, 전달 행위의 값  (0) 2010.04.02
Spring ppt 모음  (1) 2010.03.24
Spring Tutorial  (0) 2010.03.24
Spring - JPetStore[1]  (0) 2010.03.16
.
:
Posted by .07274.
.. .. ..

1> abstract 키워드란?

하위 클래스에서 반드시 오버라이딩(재정의)를 해줘야만 하는 키워드이다.
메서드와 클래스에만 쓸수 있다.

2> abstract 특징

  1. 클래스와 메서드에만 사용 가능.
  2. 메서드에서는 프로타입(선언부)만 정의, 내용(구현부)은 없다.
  3. abstract 은 final, static과 같이 쓸순없다.

3> abstract 클래스 인경우

  1. 미완성 클래스(추상메서드가 포함된 클래스는 자동으로 추상클래스가 됨)
  2. 추상클래스는 추상메서드를 포함 가능(반드시 포함해야 하는 것은 아님)
  3. 구조상 상속해서 재정의해야만 사용 가능
  4. 자체적으로 객체를 생성할 수 없음
  5. 하위클래스에서 추상메서드를 반드시 구현(오버라이딩)해야 함
  6. 형식>>> abstract class 클래스명 {.......}

4> abstract 메서드 인경우

  1. 메서드의 원형만 선언된 메서드 : 블록({})이 없는 메서드
  2. 하위 클래스에서 반드시 오버라이딩해야함.
  3. 추상메서드를 포함하는 클래스는 반드시 추상클래스
  4. 형식>>> abstract 반환형 메서드명 (인자);

5> abstract 클래스 vs abstract 메서드

  • 추상메서드를 포함하는 클래스는 반드시 추상클래스
    -- 클래스에 abstract를 표시하지 않으면 에러
  • 추상클래스는 추상메서드를 포함 가능
    -- 반드시 포함해야 하는 것은 아님
  • 하위클래스에서 상속 받은 추상메서드를 반드시 재정의해야 함




▶ 인터페이스(Interface)

 1> 인터페이스(Interface)란?

 자바에서는 다중상속(여러 클래스로부터의 동시상속)을 금지하고 있다. 이 덕분에 명확한 상속관계가 유지되지만 필요에 따라 다중 상속이 필요할 때도 있다.이런 경우를 위해서 인터페이스라는 개념이 도입되었다. 즉, 인터페이스는 다중상속을 허용해 준다.
나중에 살펴볼 이벤트에서 인터페이스를 사용하므로 반드시 개념을 이해한다.

1. 객체모델링을 통한 클래스 구성

만약 tv, 오디오, 카메라를 클래스로 작성한다고 하자. 이 세가지에는 리모컨이라는 기능이 공통적으로 가지고 있으나 서로의 기능은 다르다. 따라서 상속을 한다면 다중상속이 되지 않기 때문에 각기 따로 클래스를 작성해서 상속을 해야한다. 그러면 코딩도 많아지고 불편할 것이다. 

2. 인터페이스를 통한 클래스 구성

다중상속이 허용되는 인터페이스를 사용하는 경우 리모컨 인터페이스를 선언해서 각 클래스에서 구현해서(인터페이스를 사용하는 것은 상속이라 하지 않고 '구현'이라 한다.) 각각의 클래스에 맞게 새롭게 내용만을 정의해 주면 된다. 이는 특히 공동작업을 하는 프로그램에서 통일된 코드를 작성할 수 있다.

2> 인터페이스 특징

  1. 클래스와 메서드 선언만 하고 내용은 없다.
  2. 인터페이스 사용시 반드시 하위 클래스는 인터페이스를 오버라이딩 해야한다.
  3. 인터페이스는 자동적으로 다음과 같이 된다.
    멤버 변수 : public final static
    메서드 : public abstract
  4. 구현을 위해 implements 키워드 사용.
    예> class 클래스명 implements 인터페이스1, 인터페이스2, 인터페이스3...{....}
  5. 다중 상속이 가능 . ,(콤마)를 구분으로 여러개 의 인터페이스를 상속가능.
  6. 인터페이스 끼리 상속 가능. 이때는 extends 키워드 사용.



 



 

'I.lib() > I.lib(Java)' 카테고리의 다른 글

JNDI 란?  (1) 2010.04.08
자바 리플랙션 (Java Reflection)  (1) 2010.03.29
Javap 란? (자바 역어셈블러)  (1) 2010.03.24
POJO (Plain Old Java Object) 란?  (0) 2010.03.23
클레스 어샘블리. (Class -> Java )변환  (1) 2010.03.05
.
:
Posted by .07274.
2010. 3. 24. 16:33

Spring ppt 모음 I.lib()/I.lib(Spring)2010. 3. 24. 16:33

.. .. ..

'I.lib() > I.lib(Spring)' 카테고리의 다른 글

Spring Annotation (스프링 어노테이션)  (1) 2010.04.06
Spring 트랜잭션 격리 수준, 전달 행위의 값  (0) 2010.04.02
AOP 용어  (0) 2010.03.26
Spring Tutorial  (0) 2010.03.24
Spring - JPetStore[1]  (0) 2010.03.16
.
:
Posted by .07274.
2010. 3. 24. 16:31

Spring Tutorial I.lib()/I.lib(Spring)2010. 3. 24. 16:31

.. .. ..
Oracle & Java에서 받은 자료.


'I.lib() > I.lib(Spring)' 카테고리의 다른 글

Spring Annotation (스프링 어노테이션)  (1) 2010.04.06
Spring 트랜잭션 격리 수준, 전달 행위의 값  (0) 2010.04.02
AOP 용어  (0) 2010.03.26
Spring ppt 모음  (1) 2010.03.24
Spring - JPetStore[1]  (0) 2010.03.16
.
:
Posted by .07274.
2010. 3. 24. 10:00

Javap 란? (자바 역어셈블러) I.lib()/I.lib(Java)2010. 3. 24. 10:00

.. .. ..

java를 설치하면, bin 디렉토리 내에 다양한 실행파일들이 설치가 됩니다.

 하지만, 일반적으로 사용하는 것은 javac와 java가 대부분이죠..

 bin 디렉토리 내부를 잘 보면, javap 라는 실행파일도 있습니다.

 이글의 주제는 바로 이 javap 에 대한 얘기가 되겠습니다.

 javap는 간단하게 설명하면, 클래스 파일의 역어셈블하는 실행파일입니다.

 여기서 역어셈블이라는 것이 중요한데요, 역컴파일과는 사뭇 다릅니다.

 역컴파일은 클래스 파일을 가지고 원래 소스로 변환하는 것을 말하지만, 역어셈블은 클래스 파일의 내부의 기본 구조와 역어셈블코드(JVM의 바이너리 코드)만을 나오게 됩니다.

 특정 클래스의 내부 전체를 보고 싶은 경우는 역컴파일러를 이용하셔야 하고, 클래스 내부의 상수/함수들의 목록을 간단히 보고자 할때는 javap를 이용하는 것이 대부분입니다.

 이를 통해서 symbol not found 같은 에러를 찾는데 도움이 됩니다.

 

* 실행예

Integer 클래스의 javap 결과를 보겠습니다.

 public final class java.lang.Integer extends java.lang.Number implements java.lang.Comparable{
    public static final int MIN_VALUE;
    public static final int MAX_VALUE;
    public static final java.lang.Class TYPE;
    static final char[] digits;
    static final char[] DigitTens;
    static final char[] DigitOnes;
    public static java.lang.String toString(int,int);
    public static java.lang.String toHexString(int);
    public static java.lang.String toOctalString(int);
    public static java.lang.String toBinaryString(int);
    public static java.lang.String toString(int);
    static void appendTo(int,java.lang.StringBuffer);
    public static int parseInt(java.lang.String,int);
       throws java/lang/NumberFormatException
    public static int parseInt(java.lang.String);
       throws java/lang/NumberFormatException
    public static java.lang.Integer valueOf(java.lang.String,int);
       throws java/lang/NumberFormatException
    public static java.lang.Integer valueOf(java.lang.String);
       throws java/lang/NumberFormatException
    public java.lang.Integer(int);
    public java.lang.Integer(java.lang.String);
       throws java/lang/NumberFormatException
    public byte byteValue();
    public short shortValue();
    public int intValue();
    public long longValue();
    public float floatValue();
    public double doubleValue();
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
    public static java.lang.Integer getInteger(java.lang.String);
    public static java.lang.Integer getInteger(java.lang.String,int);
    public static java.lang.Integer getInteger(java.lang.String,java.lang.Integer);
    public static java.lang.Integer decode(java.lang.String);
       throws java/lang/NumberFormatException
    public int compareTo(java.lang.Integer);
    public int compareTo(java.lang.Object);
    static {};

[출처] javap의유용성|작성자 하자두


'I.lib() > I.lib(Java)' 카테고리의 다른 글

JNDI 란?  (1) 2010.04.08
자바 리플랙션 (Java Reflection)  (1) 2010.03.29
자바의 abstract와 인터페이스(Interface)  (0) 2010.03.24
POJO (Plain Old Java Object) 란?  (0) 2010.03.23
클레스 어샘블리. (Class -> Java )변환  (1) 2010.03.05
.
:
Posted by .07274.
.. .. ..


null처리 방식이 여러방법이있겠지만   아이바티스로만 알려드리겠습니다.(다른방법은.... DTO에서 처리 또는

인설트 하는 jsp아님 struts면 액션클래스에서 처리를 해주셔야겠지요...)

 

<sqlMap>
 
 <typeAlias alias="login" type="example.chapter10.login.loginVO" />

<resultMap id="loRes" class="login">
   <result property="id" column="id" nullValue="" />
  </resultMap>

  <sql id="jungbok">
   select id from login
  </sql>
  
  <select id="jungbokId"  resultMap="loRes">
   <include refid="jungbok"/>
    where id = #id#
  </select>

</sqlMap>

 이부분에서  resultMap에서 nullValue="" 설정해주시구요.... 말그대로 리턴될 resultMap에서 nullValue는 영어 그대로 null값입니다. 더쉽게 말해서 이 필드가 리턴될때 null값이면 nullValue에 있는 값으로 대체한다는거지요.....

 또한 DB table을 작성할시 예로..

<insert id="boardinsert" parameterClass="tempClass">
        insert into test(num,name) values(test_SEQ_num.nextval,#name:VARCHAR:NO_ENTRY#)

</insert>

 이경우는 test테이블에 추가를한다고 가정하면  위에 빨강색 글씨로 된부분처럼 #name:VARCHAR:NO_ENTRY# 이렇게 써주면 null처리가 됩니다. 당연.... 테이블 작성시 name필드는

null이 허용이 되게 만들어야겠지요...

 

 마지막으로 여담인데.... sitemesh를 이용하시는거 같아요 즉 struts2 sitemesh플러그인를 사용하시는건가봐요??? 1,2년전부터 sitemesh를 많이 사용한다고 하지만... 최근 tile2가 인기가 급상승 되었다고 합니다. 저도 써본결과 sitemesh는 사용하기는 쉽고 편하지만.. 부하가 많이 걸리고 tile2보다는 재사용성에서 떨어져서 그런거 같습니다. 공부하는 사람이라면 tiles2도 함께 알아두시면 좋을것 같습니다...tiles2도 Layout꾸며서 활용하는거에서는 개념이 같습니다......

.
:
Posted by .07274.