[Spring 레퍼런스] 4장 IoC 컨테이너 #10

이 문서는 개인적인 목적이나 배포하기 위해서 복사할 수 있다. 출력물이든 디지털 문서든 각 복사본에 어떤 비용도 청구할 수 없고 모든 복사본에는 이 카피라이트 문구가 있어야 한다.




4.10 클래스패스 스캔과 관리된 컨포넌트

이 챕터의 예제 대부분은 스프링 컨테이너에서 각 BeanDefinition를 만드는 설정메타데이터로 XML을 사용한다. 이전 섹션(Section 4.9, “어노테이션기반의 컨테이너 설정”)에서 소스레벨의 어노테이션으로 어떻게 설정 메타데이터를 사용할 수 있는지 보여주었다. 어노테이션을 사용하는 예제에서도 "base" 빈 정의는 명시적으로 XML파일에 정의하고 어노테이션은 의존성 주입에만 사용한다. 이번 섹션은 클래스패스를 스캔해서 후보 컴포넌트들을 암묵적으로 찾아내는 옵션을 설명한다. 후보 컴포넌트들은 필터 크리테리아와 일치한 클래스들이고 컨테이너에 등록된 빈 정의들 중에 대응되는 것들이다. 이는 빈 등록을 수행하는 XML을 사용하지 않아야 하고 대신 컨테이너에 등록된 빈 정를 갖는 클래스들을 선택하기 위해 어노테이션(예를 들면 @Component)이나 AspectJ 타입의 표현식이나 자신만의 커스텀 필터 크리테리아를 사용할 수 있다.

Note
스프링 3.0에서는 Spring JavaConfig project의 많은 기능들이 스프링 프레임워크 핵심의 일부가 되었다. 이는 전통적인 XML파일 대신 자바로 빈을 정의할 수 있도록 한다. 이러한 새로운 기능들을 어떻게 사용하는가에 대한 예제는 @Configuration, @Bean, @Import, @DependsOn 어노테이션을 봐라.


4.10.1 @Component와 스테레오타입(stereotype) 어노테이션
스프링 2.0 이상의 버전에서 @Repository 어노테이션은 어떤 클래스가 그 역할을 충족시켰거나 레파지토리의 stereotype (또는 데이터 접근계층이나 DAO로 알려진)이라는 표시이다. 이 표시의 사용은 Section 14.2.2, “Exception translation”에서 설명했듯이 예외의 자동 변환이다.

스프링 2.5에 도입된 스테레오타입 어노테이션: @Component, @Service, @Controller. @Component 는 스프링이 관리하는 모든 컴포넌트에 대한 제너릭 스테레오타입이다. @Repository, @Service, @Controller는 더 특정한 유즈케이스에 대한 @Component의 특수한 형태이다. 예를 들어 퍼시스턴스, 서비스, 프리젠테이션 계층에서 각각 사용한다. 그러므로 컴포넌트 클래스에 @Component 어노테이션을 붙힐 수도 있지만 대신 @Repository, @Service, @Controller 어노테이션을 붙힘으로써 클래스들이 도구가 처리하는데 더 적합하도록 할 수 있고 관점에 더 연관성이 있게 한 수 있다. 예를 들어 이러한 스테레오타입 어노테이션은 포인트컷에 대한 이상적인 타겟을 만든다. 또한 @Repository, @Service, @Controller는 스프링 프레임웍의 차기 릴리즈버전에서 추가적인 의미가 생길 가능성도 있다. 그래서 서비스계층에 @Component나 @Service 중에서 어느 것을 사용할기 선택해야 한다면 @Service가 명확하게 더 나은 선택이다. 비슷하게 앞에서 얘기했듯이 @Repository는 퍼시스턴스 계층에서 자동 예외변환에 대한 표시로서 이미 지원된다.

4.10.2 자동 클래스 탐지와 빈 정의 등록
스프링은 자동적으로 스테레오타입의 클래스들을 탐지하고 대응되는 ApplicationContext의 BeanDefinition를 등록한다. 예를 들어 다음 두 클래스는 이러한 자동탐지에 알맞는 클래스들이다.
1
2
3
4
5
6
7
8
9
10
@Service
public class SimpleMovieLister {
 
  private MovieFinder movieFinder;
 
  @Autowired
  public SimpleMovieLister(MovieFinder movieFinder) {
      this.movieFinder = movieFinder;
  }
}

1
2
3
4
@Repository
public class JpaMovieFinder implements MovieFinder {
  // 명확하도록 구현은 생략한다
}

이러한 클래스들을 자동탐지하고 대응하는 빈을 등록하려면 XML에 다음 요소를 포함시켜야 한다. base-package 요소는 두 클래스에 대한 공통 부모 팩키지이다. (대신 각 클래스의 부모 팩키지를 포함하는 리스트를 콤마로 분리해서 지정할 수도 있다.)

1
2
3
4
5
6
7
8
9
10
11
12

Note
클래스패스 패키지의 스캔은 클래스패스에서 대응되는 디렉토리 진입점이 있어야 한다. Ant로 JAR를 빌드할 때 JAR 태스크의 files-only 스위치가 켜져있지(activate) 않아야 한다.

게다가 component-scan 요소를 사용하면 AutowiredAnnotationBeanPostProcessor와 CommonAnnotationBeanPostProcessor는 둥다 암묵적으로 포함된다. 이는 두 컴포넌트가 자동으로 탐지되고 함께 연결된다. - 모두 XML에서 제공된 어떤 빈 설정 메타데이터는 없다.

Note
annotation-config 속성의 값을 false로 하면 AutowiredAnnotationBeanPostProcessor 와 CommonAnnotationBeanPostProcessor가 등록되지 않게 할 수 있다.


4.10.3 스캐닝을 커스터마이징하기 위한 필요 사용
기본적으로 @Component, @Repository, @Service, @Controller 어노테이션들이나 @Component 어노테이션이 붙은 커스텀 어노테이션이 붙은 클래스들만 후보 컴포넌트로 탐지된다. 하지만 커스텀 필터를 적용해서 간단하게 이러한 행동을 수정하거나 확장할 수 있다. component-scan 요소의 하위요소로 include-filter나 exclude-filter를 추가한다. 각 필터 요소들은 type와 expression속성을 필요로 한다. 다음 표는 필터링 옵션을 설명한다.

Table 4.5. Filter Types
필터 타입표현식 예시설명
annotationorg.example.SomeAnnotation타겟 컴포넌트에서 타입 레벨에서 표현되는 어노테이션
assignableorg.example.SomeClass타겟 컴포넌트들을 할달할 수 있는 (확장(extend)/구현(implement)) 클래스(또는 인터페이스)
aspectjorg.example..*Service+타겟 컴포넌트들과 일치되는 AspectJ 타입 표현식
regexorg\.example\.Default.*타겟 컴포넌트 클래스명과 일치되는 정규 표현식
customorg.example.MyTypeFilterorg.springframework.core.type .TypeFilter 인터페이스를 구현한 커스텀 구현체











다음 예제는 모든 @Repository 어노테이션을 무시하고 "stub" 레파지토리를 대신 사용하는 XML 설정을 보여준다.

1
2
3
4
5
6
7
8
9
<beans>
 
  <context:component-scan base-package="org.example">
     <context:include-filter type="regex" expression=".*Stub.*Repository"/>
     <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
  </context:component-scan>
 
 
</beans>

Note
<component-scan/> 요소의 속성으로 use-default-filters="false"를 지정해서 기본 필터를 사용안하도록 할 수도 있다. 이는 @Component, @Repository, @Service, @Controller 어노테이션이 붙은 클래스들을 자동 탐지하는 기능을 사용하지 않게 한다.


4.10.4 컴포넌트내에서 빈 메타데이터 정의
스프링 컴포넌트들은 컨테이너에 빈 정의 메타데이터를 제공할 수도 있다. 이는 @Configuration 어노테이션이 붙은 클래스들 내에서 빈 메타데이터를 정의하기 위해서 동일한 @Bean 어노테이션을 사용해서 할 수 있다. 다음은 간단한 예제이다.

1
2
3
4
5
6
7
8
9
10
11
12
@Component
public class FactoryMethodComponent {
 
  @Bean @Qualifier("public")
  public TestBean publicInstance() {
    return new TestBean("publicInstance");
  }
 
  public void doWork() {
    // 컴포넌트 메서드 구현체는 생략한다
  }
}

이 클래스는 내부에 doWork() 메서드가 있는 어플리케이션에 특화된 코드가 있는 스프링 컴포넌트다. 하지만 publicInstance() 메서드를 참조하는 팩토리 메서드가 있는 빈 정의도 제공한다. @Bean 어노테이션은 팩토리 매서드와 @Qualifier 어노테이션을 통한 제한자의 값같은 다른 빈 정의 프로퍼티들을 식별한다. 다른 메서드 레벨의 어노테이션들은 @Scope, @Lazy와 커스텀 qualifier 어노테이션으로 지정할 수 있다. 앞에서 얘기했듯이 추가적인 @Bean 메서드의 자동연결 지원과 함께 필드와 메서드들의 자동연결을 지원한다.

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
@Component
public class FactoryMethodComponent {
 
  private static int i;
 
  @Bean @Qualifier("public")
  public TestBean publicInstance() {
    return new TestBean("publicInstance");
  }
 
  // 커스텀 qualifier와 메서드 파라미터의 자동연결의 사용
 
  @Bean
  protected TestBean protectedInstance(@Qualifier("public") TestBean spouse, @Value("#{privateInstance.age}") String country) {
    TestBean tb = new TestBean("protectedInstance", 1);
    tb.setSpouse(tb);
    tb.setCountry(country);
    return tb;
  }
 
  @Bean @Scope(BeanDefinition.SCOPE_SINGLETON)
  private TestBean privateInstance() {
    return new TestBean("privateInstance", i++);
  }
 
  @Bean @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
  public TestBean requestScopedInstance() {
    return new TestBean("requestScopedInstance", 3);
  }
}

예제는 String 메서드 파라미터 country를 또 다른 빈 privateInstance의 Age 프로퍼티의 값으로 자동연결한다. 스프링 표현언어(Spring Expression Language)요소는 #{ <expression> } 문법으로 프로퍼티의 값을 정의한다. @Value 어노테이션에 대한 표현식 리졸버는 표현식 문자를 처리할 때 빈 이름을 찾으려머 먼저 설정된다.

스프링 컴포넌트의 @Bean 메서드들은 스프링 @Configuration 클래스 내부의 @Bean 메서드들과는 다르게 수행된다. @Component 클래스들이 메서드와 필드의 호출을 가로채려고 CGLIB로 향상(enhanced)되지 않는다는 것이 차이점이다. CGLIB 프록싱은 @Configuration 클래스의 @Bean 메서드내에서 메서드와 필드를 호출하는 것은 협력객체를 참조하는 빈 메타데이터를 생성한다. 메서드들은 일반적인 자바 시맨틱으로 호출되지 않는다. 반면에 @Component 클래스의 @Bean 메서드내에서 메서드나 필드를 호출하는 것은 표준 자바 시맨틱을 갖는다.

4.10.5 이름으로 자동탐지되는 컴포넌트
스캐닝 과정 중에 컴포넌트를 자동탐지했을 때 그 빈의 이름은 해당 스캐너가 알고 있는 BeanNameGenerator 전략에 의해 생성된다. 기본적으로 name 값이 있는 어떤 스프링 스테레오타입 어노테이션 (@Component, @Repository, @Service, @Controller)도 name 값에 따라서 대응되는 빈 정의에 이름을 제공할 것이다.

어노테이션이 name 값이 없거나 탐지된 다른 컴포넌트(커스텀 필터로 발견된 컴포넌트 같은)가 있다면 기본 빈이름 생성기는 대문자로 쓰지 않고 정규화되지 않은 클래스명을 리턴한다. 예를 들어 다음 두 컴포넌트가 담지되었다면 이름은 myMovieLister와 movieFinderImpl가 될 것이다.

1
2
3
4
@Service("myMovieLister")
public class SimpleMovieLister {
  // ...
}

1
2
3
4
@Repository
public class MovieFinderImpl implements MovieFinder {
  // ...
}

Note
기본 빈이름 전력에 의존하고 싶지 않다면 커스텀 빈이름 전략을 제공할 수 있다. 일단 BeanNameGenerator 인터페이스를 구현하고 아규먼트가 없는 기본 생성자를 만든다. 그 다음 스캐너를 설정할 때 정규화된 클래스명을 제공해라.

1
2
3
4
5
<beans>
 
  <context:component-scan base-package="org.example" name-generator="org.example.MyNameGenerator" />
 
</beans>

일반적인 규칙에 따라 다른 컴포넌트들을 명시적으로 참조하도록 만들 때마다 어노테이션에 이름을 지정하는 것을 고려해라. 반면 컨테이너가 연결에 대한 책임이 있는 경우에는 자동생성되는 이름으로 충분하다.

4.10.6 자동탐지된 컴포넌트에 범위(scope) 제공하기
보통의 스프링이 관리하는 컴포넌트처럼 자동탐지된 컴포넌트의 기본 범위와 가장 일반적인 범위는 싱글톤이다. 하지만 때로는 다른 범위가 필요하고 스프링 2.5가 제공하는 새로운 @Scope 어노테이션을 제공한다. 어노테이션에 범위의 이름을 지정하면 된다.

1
2
3
4
5
@Scope("prototype")
@Repository
public class MovieFinderImpl implements MovieFinder {
  // ...
}

Note
어노테이션에 기반한 접근대신에 커스텀 범위 처리 전략을 제공하려면 ScopeMetadataResolver 인터페이스를 구현하고 아규먼트가 없는 기본 생성자를 만들어라. 그 다음 스캐너를 설정할 때 정규화된 클래스명을 제공해라.

1
2
3
4
5
<beans>
 
  <context:component-scan base-package="org.example" scope-resolver="org.example.MyScopeResolver" />
 
</beans>

싱글톤이 아닌 어떤 범위를 사용하면 범위를 가진 객체에 대한 프록시를 생성할 필요가 있을 수 있다. 프록시가 필요한 이유는 Section 4.5.4.5, “의존성에서 범위를 가진 빈”에서 설명했다. 이 목적을 위해 component-scan 요소에서 scoped-proxy 속성을 사용할 수 있다. 이 속성에는 no, interfaces, targetClass 세 가지 값을 지정할 수 있다. 예를 들어 다음 설정은 표준 JDK 다이나믹 프록시의가 될 것이다.

1
2
3
4
5
<beans>
 
  <context:component-scan base-package="org.example" scoped-proxy="interfaces" />
 
</beans>

4.10.7 어노테이션으로 qualifier 메타데이터 제공하기
@Qualifier 어노테이션은 Section 4.9.3, “qualifiers를 사용한 어노테이션 기반 자동연결의 미세조정”에서 이야기 했다. 해당 섹션의 예제들은 자동연결 후보를 처리할 때 세밀한 제어를 제공하는 @Qualifier 어노테이션과 커스텀 qualifier 어노테이션의 사용방법을 보여준다. 이 예제들은 XML 빈 정의에 기반하기 때문에 qualifier 메타데이터는 XML의 bean 요소의 하위요소로 qualifier나 meta 사용하는 후보 빈 정의에서 제공된다. 컴포넌트 자동탐지를 클래스패스에 기반해서 스캔할 때는 후보 클래스의 타입레벨 어노테이션으로 qualifier 메타데이터를 제공한다. 다음 세 가지 예제는 이러한 기법을 보여준다.

1
2
3
4
5
@Component
@Qualifier("Action")
public class ActionMovieCatalog implements MovieCatalog {
  // ...
}

1
2
3
4
5
@Component
@Genre("Action")
public class ActionMovieCatalog implements MovieCatalog {
  // ...
}

1
2
3
4
5
@Component
@Offline
public class CachingMovieCatalog implements MovieCatalog {
  // ...
}

Note
어노테이션에 기반한 대부분의 대체방법들 처럼 어노테이션 메타데이터는 클래스 정의 자체와 밀접한 관계가 된다는 것을 기억해야 한다. 반면 XML을 사용하면 해당 메타데이터가 클래스마다가 아니라 인스턴스마다 제공되기 때문에 qualifier 메타데이터에서 다양함을 제공하기 위해 같은 타입의 여러 가지 빈을 사용할 수 있다.



출처 - http://blog.outsider.ne.kr/778


===================================================================================


스프링 2.5가 드디어 릴리즈 되었네요.
좀 천천히 관심 둘 여유있을 줄 알았는데... 플젝 투입되어 있어서 정신이 없습니다.

19일, 인포큐에 스프링 2.5의 새로운  부분에 대한 글이 올라왔었습니다.
 
http://www.infoq.com/articles/spring-2.5-part-1

그냥 이런게 올라왔었구나... 나중에 읽어야지.. 하고 미뤄두었었는데 릴리즈도 된 마당에 대충이라도 읽어봤습니다.

2.0에서 XML 스키마 지원으로 스프링을 즐겁게 쓰도록 만들어 주었었는데... 이번에는 더욱 단순하고 강력한 스프링이 되었다고 하네요. 2.0은 2.5로 가기 위한 맛보기...ㅎㅎ

개인적으로 어노테이션을 통한 설정이 생각 만큼 생산성을 높여줄지에 대해서는 의문이지만 XML를 끔찍하게 여기는 사람들이 많기 때문에 매우 환영할만 하다고 생각합니다.

이왕 글을 쓴거 위 글의 내용을 약간 요약해보겠습니다. infoq에 기고된 글의 저작권이 어찌되는지 모르지만 요약 정도는 상관 없겠죠?

이 글은 총 3회에 나눠서 쓰여질 기고문의 첫번째에 해당합니다. 주로 어노테이션과 관련된 부분에 대해서 설명하고있구요.두번째 글은 Web Tier 쪽을, 마지막 글은 통합과 테스팅에 관련된 기술을 논하려고 한답니다. 아마도 두번째는SpringMVC를 마지막은 JUnit 4 지원과 OSGi가 될 듯 하네요.

JSR-250 어노테이션 지원

스프링 2.5에 새로 지원하는 어노테이션은 다음과 같다고 합니다.

  • @Resource
  • @PostConstruct
  • @PreDestroy
@Resource

DI를 위해서 사용합니다. 
빈 컨테이너 안의 빈들 중에서 지정된 이름의 빈을 찾아서 DI를 해줍니다. 아래 예에서라면 스프링은 관라하는 빈들 중 이름이 dataSource인 놈을 가지고 setDataSource()를 호출하는거죠.
@Resource(name="dataSource")
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
직접 맴버 변수에 지정할 수도 있는데 이렇게 하면 setter 없이도 DI가 된다네요. 요거 맘에 듭니다. 

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

위의 예에서 처럼 이름을 지정하지 않으면 변수 이름이 자동으로 사용되네요. 아래처럼 setter 메소드에 이름 없이 지정 할 수도 있다고 합니다.
private DataSource dataSource;
@Resource
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
이름으로 빈을 찾았는데 없으면 타입으로 찾아서 인젝션 해준답니다. 원하지 않으면 이 기능을 끌 수도 있습니다.

Lifecycle 어노테이션 @PostConstruct와 @PreDestory

기존에 빈 생성시 빈을 초기화하고 소멸시 정리하는 작업을 하려면 InitializingBean과 DesposableBean 인터페이스를 상속하거나 빈설정시 명시적으로 초기화 메소드와 정리 메소드를 지정해 주었어야 합니다.
인터페이스를 사용하면 자동화 되어 좋기는 하지만 스프링 디펜던시가 생기고 - 솔직히 이 빈을 다른 곳에서 쓸 일이 얼마나 있겠냐만 늘 결벽증 때문에 사용안하게 된다죠 - 그래서 설정을 주로 사용하곤 했습니다.

사용은 간단합니다. 초기화 메소드와 정리 메소드 위에 각 어노테이션을 표기만 하면 되는거죠.

public class FilePoller {

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

@PreDestroy
public void stopPolling() {
...
}
...
} 
늘 XML 설정 할 때 마다 빼먹을까봐 신경 썼었는데 좋네요.

정밀한 오토와이어링

2.5 이전에도 여러가지 오토와이어링 방법을 제공했습니다. 컨스트럭터, 셋터의 타입, 셋터의 이름, 자동인식.... 하지만 전체적으로어떤 것을 선택할지 설정 할 수는 있어도 어떤 경우에는 타입으로 찾고 어떤 경우에는 이름으로 찾을지 정밀하게 제어 할 수는 없었습니다.

위에서 말한 것 처럼 2.5에서는 @Resource 어노테이션으로 메소드별 필드별로 이름 기반의오토와이어링을 지정 할 수 있게 되었습니다. 하지만 이건 제약이 있어 스프링 2.5에서는 @Autowired 어노테이션을추가했다고 합니다. 이건 비표준인거죠. 스프링 디펜던시가 생깁니다.

@Autowired 어노테이션은 컨스트럭터, 메소드, 필드에 사용하며 타입으로 오토와이어링 하도록 지정하는 기능을 가지고 있습니다. 그런데 메소드가 꼭 셋터일 필요는 없습니다. 심시어 패러미터가 여러개인 경우도 상관 없답니다. 오호...
@Autowired
public void setup(DataSource dataSource, AnotherObject o) { ... }

기본적으로 이 어노테이션으로 표시된 항목은 필수인 것으로 처리되지만 required 옵션을 false로 하면 빈을 못 찾아도 그냥 넘어갑니다. 예를 들어 다음에서 빈을 못찾으면 그냥 하드코딩한 DefaultStrategy가 사용되는거죠.

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

이렇게 타입으로 빈을 찾는데 해당 타입의 빈이 하나 이상일 경우 스프링은 오토와이어링이 실패한 것으로 처리합니다. 이 문제를 해결하기 위한 몇가지 방법이 있습니다. 우선 빈 설정에서 primary 속성을 사용하는 방법이 있다.

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

이번 2.5에는 보다 정밀한 제어가 가능한데 @Qualifier 어노테이션을 사용하면 빈 이름을 지정할 수 있다. 타입이 아닌 이름으로 찾게 됩니다.

@Autowired
@Qualifier("primaryDataSource")
private DataSource dataSource; 

이 어노테이션을 별도로 만든 이유는 다음 처럼 사용할 수 있게 하려는 것이라네요. 머리도 좋아요. 이 어노테이션은 컨스트럭터 매개변수, 필드, 메소드 매개변수 어디에도 쓸 수 있답니다.

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

이 뿐 아니라 커스텀 어노테이션을 사용한 인젝션에도 사용될 수 있다는데요. 요건 읽기 귀찮아서 일단 PASS...

스프링 컴포넌트 자동 인식

스프링 2.0부터 스테레오 타입 개념의 어노테이션이 도입되었습니다. @Repository는 데이타 억세스 코드라는 표시를 하는 어노테이션으로 사용된 것이죠.
2.5에는 일반적인 3-Tier 아키택쳐에서의 역활을 표기하기 위해 @Service와 @Controller라는 어노테이션을 추가했습니다. 이와 함께 제너릭 어노테이션인 @Component도 추가...

이들 어노테이션들은 객체에 역할을 부여해서 AOP나 후처리기가 뭔가 추가적인 작업을 하도록 해줍니다.

이 어노테이션들로 사용할 수 있는 새 기능 중 하나가 컴포넌트 자동 인식 기능... 오토와이어링을 쓰더라도 기본적인 빈 설정을 해주었어야 했지만 이 컴포넌트 자동 탐색 기능을 쓰면 이 기본적인 빈 설정 조차 필요없게 됩니다.

2.5의 PetClinic 샘플을 보면 하부구조에 해당하는 컴포넌트들은 XML에 설정이 되어 있지만 Web Tier 컨트롤러들은 자동 인식 기능을 사용하도록 되어 있다는군요. 저도 처음 이 기능을 들었을 때에 Web Tier에 적용하면 좋겠다고 생각되더군요. XML의 명시적이고 중앙집중적인 특징도 무시는 못하죠. 개발할 때에는 편의상 오토와이어링을 쓰더라도 운영환경에서는 XML이 역시... 혹시 새로 생긴 자동 탐색 기능과 오토와이어링 기능으로 구성된 빈 컨테이너의 내용을 XML로 생성해주는 방법이 있다면 좀 알려주세요.

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

이렇게 지정된 패키지 안의 클래스들을 탐색해서 스테레오타입이 지정된 클래스들을 찾아냅니다. 예를 들면 이런 Spring MVC 컨트롤러...

@Controller

public class ClinicController {

private final Clinic clinic;

@Autowired
public ClinicController(Clinic clinic) {
this.clinic = clinic;
}
... 

탐색 규칙을 커스터마이제이션 할 수도 있습니다. 다음과 같이 하면 스테레오 타입을 찾는 기본 룰은 사용하지 않고 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 어노테이션을 제외시킵니다.

<context:component-scan base-package="example">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan> 

 물론 커스텀 어노테이션을 탐색에 사용하게 할 수도 있습니다. @Generic 제넥릭 어노테이션으로 다음과 같이 커스텀 어노테이션에 @Generic 어노테이션을 사용하면

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface BackgroundTask {
String value() default "";
} 

이 어노테이션이 지정된 객체들은 모두 스프링 객체로 인식이 됩니다.

@BackgroundTask
public class FilePoller {

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

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

이렇게 자동 인식된 빈들은 클래스 이름으로 등록이 됩니다. 위의 예에 나오는 FilePoller 클래스는 filePoller라는 이름으로 스프링에 등록되는거죠. 만약 다른 이름을 원하면 이렇게 합니다.

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

기본적으로 스프링은 빈을 싱글톤으로 관리하지만 다른 스코프를 써야 할 경우도 있습니다. 이 경우는 요렇게...

@Component
@Scope("session")
public class ShoppingCart {
...
} 

전 지금 진행중인 프로젝트에 2.5를 적용할 예정입니다. 원래 아발론으로 만들어진 서버 프로그램인데 스프링으로 바꾸고 있거든요. 

프로그래밍이 즐거워지네요. ㅎㅎ

아! 아시겠지만 제가 잘못 이해해서 생긴 오류에 대해서는 책임 안집니다. ;;;


출처 - http://gyumee.egloos.com/1026938


===================================================================================


최근에는 본의 아니게 AJAX로 먹고 살고 있지만, 내 밥줄은 기본적으로 자바다. 그리고, 내가 자바로 코딩할 때 가장 많이 사용하는 라이브러리(프레임웍을 포함해서) 중의 하나가 spring이다. 즐겨쓰던 IoC 컨테이너였던 avalon 프로젝트가 뽀개지면서 대안으로 spring 1.2.x를 처음 쓰기 시작했는데, 벌써(이제서야?) 2.5 버전이 나왔다.

프레임웍 라이브러리의 특성상(하위호환성이 무척 중요하다!) 큰 변화가 있기 힘들지만, 2.5에서는 호환성을 깨지 않으면서 많은 눈에 띄는 변화가 있었다. 이 글에서는 그 중에서 annotation 지원에 대해서 알아보겠다.

스테레오타입 어노테이션

클래스에 붙여서 해당 클래스가 컴포넌트 스캐닝의 대상이고, 스프링에 의해서 관리될 것임을 표시한다. 즉, <beans> XML 설정 파일에서 <bean>으로 선언한 것과 같은 효과를 낸다.

@Component 
메타 어노테이션. 다른 모든 스프링 스테레오타입 어노테이션 및 커스텀 Qualifer 어노테이션의 부모 어노테이션.

@Service
상태없는 서비스 컴포넌트.

@Repository

저장소 컴포넌트(DAO 등).

@Aspect
@AspectJ의 어스펙트.

@Controller
Spring MVC 컨트롤러.

스테레오타입은 스테레오타입일 뿐!! 너무 심각한 의미를 부여하지 말자! 대부분의 경우엔 @Service으로 충분하다. @Controller에 대해서는 다음 기회에 좀 더 자세히 알아보기로 하고...

위의 어노테이션이 붙은 클래스를 찾기 위해서 모든 클래스 패스를 뒤지는 것은 곤란하므로.. 아래와 같은 방식으로 스캔할 범위를 지정한다:

예) 가장 단순한 사용 예: 특정 패키지 이하의 모든 클래스에 대해서 스테레오타입 어노테이션이 붙은 클래스를 찾아서 스프링 관리 대상에 포함 시킴.(빈 선언)

<beans>
  <context:component-scan base-package="com.mycompany.myblog" />
   ...
</beans>


의존성 주입(DI; Dependency Injection) 어노테이션

@Autowired
생성자, 메소드, 필드에 붙여서 스프링을 통해 인젝션될 것임을 표시한다.

@Qualifier
@Autowired이 붙은 필드 또는 메소드의 인자에 붙여서 인젝션할 빈을 검색하기 위한 더 정확한 조건을 지정한다.


예) 필드에 지정
@Autowired
@Qualifier("myDataSource“)
private DataSource orderDataSource


예) 메소드에 지정
@Autowired
public void createTemplates(DataSource ds, ConnectionFactory cf) {
   this.jdbcTemplate = new JdbcTemplate(ds);
   this.jmsTemplate = new JmsTemplate(cf);
}


예) @Qualifer와 함께 지정
public class JdbcOrderRepositoryImpl implements OrderRepository {
   @Autowired
   public void init(
      @Qualifier("myDataSource“) DataSource orderDataSource, 
      @Qualifier("otherDataSource") DataSource inventoryDataSource, 
      MyHelper autowiredByType) {
         // ...
  }
  ...
}


JSR-250 어노테이션

JSR-250은 BEA WebLogic에서 제공되던 것을 JSR을 통해 표준화한 것인데, @Resource어노테이션은 JNDI 리소스 인젝션을 위해 꽤 많이 쓰이고 있는 것 같다.

@Resource
JSR-250에서는 JNDI 리소스만 인젝션할 수 있었지만, 스프링 2.5에서는 스프링을 통해 관리되는 모든 빈을 인젝션할 수 있다. 

@PostConstruct
2.0에서는 InitializingBean 인터페이스를 구현하고 afterPropertiesSet()에서 수행하거나, bean설정에서 init-method 속성으로 지정했다.

@PreDestory
2.0에서는 DisposableBean 인터페이스를 구현하고 destroy()를 정의하거나, bean설정에서 destroy-method 속성으로 지정했다.

개인적으로 스프링 전용인 @Autowired보다는 @Resource를 선호하는 편인데, @Qualifer를 쓸 수 없다는 단점이 있지만, @Resource(name="dataSource")처럼 빈 이름을 지정할 수 있으므로 대부분의 경우엔 충분하다.

백문불여일견, 백견불여일타, 백타불여일런!

예) 스프링 2.0.x (스프링에 대한 컴파일 타임 의존성이 없음)
public class JdbcBlogdao implement BlogDao {
   private DataSource dataSource;
   public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; }
   public void init() throws Exception { ... }
   public void destroy() throws Exception { ... }
   ...
}

<beans>
   <bean id="blogDao" class="mypackage.JdbcBlogDao" init-method="init" destroy-method="destroy">
      <property name="dataSource" ref="dataSource />
      ...
   </bean>
   ...
</beans>

예) 스프링 2.0.x(스프링에 대한 컴파일 타임 의존성을 가짐) 
public class JdbcBlogdao implement BlogDao, InitializingBeanDisposableBean {
   private DataSource dataSource;
   public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; }
   public void afterPropertiesSet() throws Exception { ... }
   public void destroy() throws Exception { ... }
   ...
}

<beans>
   <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">...</bean>
   <bean id="blogDao" class="mypackage.JdbcBlogDao">
      <property name="dataSource" ref="dataSource />
      ...
   </bean>
   ...
</beans>

예) 스프링 2.5(어노테이션과 컴포넌트 스캔을 사용)
@Repository("blogDao")
public class JdbcBlogDao implements BlogDao {
   @Resource
   private DataSource dataSource;
   @PreConstruct
   public void init() throws Exception { ... }
   @PostDestroy
   public void destroy() throws Exception { ... }
   ...
}

<beans>
   <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">...</bean>
   <context:component-scan base-package="com.mycompany.myblog" /> 
   ...
</beans>


다음에는 "Spring MVC 어노테이션"에 대해서 알아볼 생각인데...
틈나는대로 적겠지만, 그 전에 2.6이 나올지도... -.-;


출처 - http://iolothebard.tistory.com/313












'Framework & Platform > Spring' 카테고리의 다른 글

Spring MVC - TilesView - tiles 2 연동  (0) 2012.05.11
spring mvc - No mapping found for HTTP request with URI  (0) 2012.05.10
spring - annotation 1  (0) 2012.05.09
Sping MVC - Model  (0) 2012.05.09
Spring - @Controller  (0) 2012.05.09
Posted by linuxism
,