[java] <context : annotation-config>와 <context : component-scan>의 차이점

나는 봄 3을 배우고 난 기능성 뒤에를 파악하지 못하는 것 같습니다 <context:annotation-config><context:component-scan>.

내가 읽은 것에서 그들은 다른 주석 ( @Required, @Autowiredetc vs , 등) 을 처리하는 것처럼 보이지만 @Component, 읽은 것에서도 동일한 bean post processor 클래스를 등록합니다 .@Repository@Service

나를 더 혼란스럽게하기 위해에 annotation-config 속성이 있습니다 <context:component-scan>.

누군가이 태그를 밝힐 수 있습니까? 무엇이 비슷한가, 무엇이 다른가, 하나는 다른 것으로 대체되고, 그들은 서로를 완성하며, 나는 그들 중 하나가 필요합니까?



답변

<context:annotation-config> 응용 프로그램 컨텍스트에 이미 등록 된 Bean에서 주석을 활성화하는 데 사용됩니다 (XML 또는 패키지 스캔으로 정의 된 경우에 상관없이).

<context:component-scan>또한 무엇을 할 수 <context:annotation-config>않고 <context:component-scan>애플리케이션 컨텍스트 내에서 콩을 찾아 등록 패키지를 스캔도.

차이점 / 유사성을 보여주기 위해 몇 가지 예를 사용하겠습니다.

세 종류의 콩의 기본 설정으로 시작하자 A, BC함께 B그리고 C주입되는 A.

package com.xxx;
public class B {
  public B() {
    System.out.println("creating bean B: " + this);
  }
}

package com.xxx;
public class C {
  public C() {
    System.out.println("creating bean C: " + this);
  }
}

package com.yyy;
import com.xxx.B;
import com.xxx.C;
public class A { 
  private B bbb;
  private C ccc;
  public A() {
    System.out.println("creating bean A: " + this);
  }
  public void setBbb(B bbb) {
    System.out.println("setting A.bbb with " + bbb);
    this.bbb = bbb;
  }
  public void setCcc(C ccc) {
    System.out.println("setting A.ccc with " + ccc);
    this.ccc = ccc; 
  }
}

다음과 같은 XML 구성을 사용하십시오.

<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A">
  <property name="bbb" ref="bBean" />
  <property name="ccc" ref="cBean" />
</bean>

컨텍스트를로드하면 다음과 같은 출력이 생성됩니다.

creating bean B: com.xxx.B@c2ff5
creating bean C: com.xxx.C@1e8a1f6
creating bean A: com.yyy.A@1e152c5
setting A.bbb with com.xxx.B@c2ff5
setting A.ccc with com.xxx.C@1e8a1f6

이것은 예상 된 결과입니다. 그러나 이것은 “오래된 스타일”봄입니다. 이제 주석이 있으므로 주석을 사용하여 XML을 단순화 할 수 있습니다.

먼저 다음 bbb과 같이 cccbean 에서 and 속성을 자동 와이어 링합니다 A.

package com.yyy;
import org.springframework.beans.factory.annotation.Autowired;
import com.xxx.B;
import com.xxx.C;
public class A { 
  private B bbb;
  private C ccc;
  public A() {
    System.out.println("creating bean A: " + this);
  }
  @Autowired
  public void setBbb(B bbb) {
    System.out.println("setting A.bbb with " + bbb);
    this.bbb = bbb;
  }
  @Autowired
  public void setCcc(C ccc) {
    System.out.println("setting A.ccc with " + ccc);
    this.ccc = ccc;
  }
}

이를 통해 XML에서 다음 행을 제거 할 수 있습니다.

<property name="bbb" ref="bBean" />
<property name="ccc" ref="cBean" />

내 XML은 이제 다음과 같이 단순화되었습니다.

<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A" />

컨텍스트를로드하면 다음과 같은 결과가 나타납니다.

creating bean B: com.xxx.B@5e5a50
creating bean C: com.xxx.C@54a328
creating bean A: com.yyy.A@a3d4cf

좋아, 이건 잘못이야! 어떻게 된 거예요? 왜 내 속성이 자동으로 연결되지 않습니까?

주석은 좋은 기능이지만 그 자체로는 아무것도하지 않습니다. 그들은 단지 주석을 달았습니다. 주석을 찾아서 처리하려면 처리 도구가 필요합니다.

<context:annotation-config>구조에. 이는 자체 정의 된 동일한 애플리케이션 컨텍스트에 정의 된 Bean에서 찾은 주석에 대한 조치를 활성화합니다.

XML을 다음과 같이 변경하면

<context:annotation-config />
<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A" />

응용 프로그램 컨텍스트를로드하면 올바른 결과가 나타납니다.

creating bean B: com.xxx.B@15663a2
creating bean C: com.xxx.C@cd5f8b
creating bean A: com.yyy.A@157aa53
setting A.bbb with com.xxx.B@15663a2
setting A.ccc with com.xxx.C@cd5f8b

좋아, 이것은 훌륭하지만 XML에서 두 개의 행을 제거하고 하나를 추가했습니다. 큰 차이는 아닙니다. 주석이있는 아이디어는 XML을 제거해야한다는 것입니다.

XML 정의를 제거하고 주석으로 모두 바꾸자.

package com.xxx;
import org.springframework.stereotype.Component;
@Component
public class B {
  public B() {
    System.out.println("creating bean B: " + this);
  }
}

package com.xxx;
import org.springframework.stereotype.Component;
@Component
public class C {
  public C() {
    System.out.println("creating bean C: " + this);
  }
}

package com.yyy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.xxx.B;
import com.xxx.C;
@Component
public class A { 
  private B bbb;
  private C ccc;
  public A() {
    System.out.println("creating bean A: " + this);
  }
  @Autowired
  public void setBbb(B bbb) {
    System.out.println("setting A.bbb with " + bbb);
    this.bbb = bbb;
  }
  @Autowired
  public void setCcc(C ccc) {
    System.out.println("setting A.ccc with " + ccc);
    this.ccc = ccc;
  }
}

XML에서 우리는 이것을 유지합니다.

<context:annotation-config />

컨텍스트를로드하면 결과는 … Nothing입니다. Bean이 작성되지 않고 Bean이 자동 연결되지 않습니다. 아무것도!

첫 번째 단락에서 말했듯 <context:annotation-config />이 응용 프로그램 컨텍스트에 등록 된 Bean에서만 작동 하기 때문 입니다. 세 개의 Bean에 대한 XML 구성을 제거했기 때문에 작성된 Bean <context:annotation-config />이없고 작업 할 “대상”이 없습니다.

그러나 <context:component-scan>“대상”이 작동하도록 패키지를 스캔 할 수 있는 문제는 아닙니다 . XML 구성의 내용을 다음 항목으로 변경하십시오.

<context:component-scan base-package="com.xxx" />

컨텍스트를로드하면 다음과 같은 결과가 나타납니다.

creating bean B: com.xxx.B@1be0f0a
creating bean C: com.xxx.C@80d1ff

흠 … 뭔가 빠졌습니다. 왜?

당신이 클래스에 closelly 보면, 클래스는 A패키지를 가지고 com.yyy하지만 난에서 지정한 <context:component-scan>패키지를 사용하는 com.xxx이 완전히 내 놓친 있도록 A클래스를 만 포착 B하고 C어느에있는 com.xxx패키지.

이 문제를 해결하기 위해 다른 패키지도 추가합니다.

<context:component-scan base-package="com.xxx,com.yyy" />

이제 예상 결과를 얻습니다.

creating bean B: com.xxx.B@cd5f8b
creating bean C: com.xxx.C@15ac3c9
creating bean A: com.yyy.A@ec4a87
setting A.bbb with com.xxx.B@cd5f8b
setting A.ccc with com.xxx.C@15ac3c9

그리고 그게 다야! 이제 더 이상 XML 정의가 없으며 주석이 있습니다.

최종 예를 들어, 주석 클래스를 유지 A, B그리고 C우리는 컨텍스트를로드 한 후 무엇을 얻을 것이다, 그리고 XML에 다음을 추가?

<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />

우리는 여전히 올바른 결과를 얻습니다.

creating bean B: com.xxx.B@157aa53
creating bean C: com.xxx.C@ec4a87
creating bean A: com.yyy.A@1d64c37
setting A.bbb with com.xxx.B@157aa53
setting A.ccc with com.xxx.C@ec4a87

클래스의 Bean을 A스캔하여 확보하지 않더라도 처리 도구는 여전히 <context:component-scan>애플리케이션 컨텍스트에 등록 된 모든 Bean에 적용되며 A, XML에 수동으로 등록 된 경우 에도 마찬가지입니다 .

그러나 만약 우리가 다음과 같은 XML을 가지고 있다면, <context:annotation-config />그리고 둘 다 지정했기 때문에 중복 된 bean을 얻게 <context:component-scan>될까요?

<context:annotation-config />
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />

아니요, 중복이 없습니다. 다시 예상 결과를 얻습니다.

creating bean B: com.xxx.B@157aa53
creating bean C: com.xxx.C@ec4a87
creating bean A: com.yyy.A@1d64c37
setting A.bbb with com.xxx.B@157aa53
setting A.ccc with com.xxx.C@ec4a87

두 태그가 동일한 처리 도구를 지정하기 때문입니다 (지정된 <context:annotation-config />경우 생략 가능 <context:component-scan>). 그러나 Spring은 한 번만 실행을 처리합니다.

처리 도구를 여러 번 직접 등록하더라도 Spring은 여전히 ​​한 번만 마법을 수행하도록합니다. 이 XML :

<context:annotation-config />
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />
<bean id="bla" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean id="bla1" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean id="bla2" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean id="bla3" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />

여전히 다음과 같은 결과가 생성됩니다.

creating bean B: com.xxx.B@157aa53
creating bean C: com.xxx.C@ec4a87
creating bean A: com.yyy.A@25d2b2
setting A.bbb with com.xxx.B@157aa53
setting A.ccc with com.xxx.C@ec4a87

좋아, 랩은 끝이야.

@Tomasz Nurkiewicz와 @Sean Patrick Floyd의 답변과 함께이 정보가 방법 <context:annotation-config><context:component-scan>작업 을 이해하는 데 필요한 모든 것이기를 바랍니다
.


답변

어떤 주석이 어떤 선언에 의해 선택되었는지에 대한 멋진 요약 을 발견했습니다 . 그것을 연구하면 다음 <context:component-scan/>과 같이 인식되는 주석의 상위 집합 을 인식합니다 <context:annotation-config/>.

  • @Component, @Service, @Repository, @Controller,@Endpoint
  • @Configuration, @Bean, @Lazy, @Scope, @Order, @Primary, @Profile, @DependsOn, @Import,@ImportResource

보시다시피 CLASSPATH 구성 요소 검색 및 Java @Configuration 기능 <context:component-scan/>으로 논리적으로 확장 <context:annotation-config/> 됩니다.


답변

Spring을 사용하면 두 가지 작업을 수행 할 수 있습니다.

  1. 콩의 자동 배선
  2. 콩의 자동 발견

1. 자동 배선
보통 applicationContext.xml 에서 bean을 정의하고 다른 bean은 생성자 또는 setter 메소드를 사용하여 연결됩니다. XML 또는 주석을 사용하여 Bean을 연결할 수 있습니다. 주석을 사용하는 경우 주석을 활성화해야 <context:annotation-config />하며 applicationContext.xml 에 추가해야
합니다 . 이는 bean (생성자 또는 setter)을 수동으로 연결할 필요가 없기 때문에 applicationContext.xml 의 태그 구조를 단순화합니다 . @Autowire주석 을 사용할 수 있으며 콩은 유형별로 연결됩니다.

수동 XML 구성을 피하기위한 단계는 다음과 같습니다.

2. 자동
검색 자동 검색은 applicationContext.xml에<bean> 태그를 너무 추가 할 필요가 없다는 의미에서 XML을 한 단계 더 단순화합니다 . 다음 주석 중 하나를 사용하여 특정 Bean을 표시하면 Spring은 표시된 Bean 및 해당 종속성을 Spring 컨테이너에 자동으로 연결합니다. 주석은 다음과 같습니다 : @Controller , @Service , @Component , @Repository . 기본 패키지 를 사용 하고 가리키면 Spring은 구성 요소를 자동 검색하여 Spring 컨테이너에 연결합니다.<context:component-scan>


결론적으로 :

  • <context:annotation-config />@Autowired 주석 을 사용하기 위해 사용
    됩니다
  • <context:component-scan /> 특정 Bean의 검색 및 자동 배선 시도를 판별하는 데 사용됩니다.

답변

<context:annotation-config> XML에 정의되어 있는지 또는 구성 요소 검색을 통해 Bean에있는 여러 가지 주석을 활성화합니다.

<context:component-scan> XML을 사용하지 않고 Bean을 정의하기위한 것

자세한 내용은 다음을 읽으십시오.


답변

둘의 차이점은 정말 간단합니다.

<context:annotation-config /> 

Bean의 특성과 생성자 만 연결하도록 제한된 주석을 사용할 수 있습니다.

어디로

<context:component-scan base-package="org.package"/> 

모든 것을 가능하게 <context:annotation-config />고정 관념 예를 들어, 사용의 추가와 함께, 할 수 … @Component, @Service, @Repository. 따라서 생성자 또는 속성에만 국한되지 않고 전체 Bean을 연결할 수 있습니다!.


답변

<context:annotation-config>: spring config xml에 이미 등록 된 Bean에 대한 주석 스캔 및 활성화.

<context:component-scan>: 콩 등록 +<context:annotation-config>


@Autowired 및 @Required대상 특성 레벨 이므로이 주석을 사용하기 전에 Bean이 스프링 IOC에 등록해야합니다. 이러한 주석을 사용하려면 각 Bean을 등록하거나 포함해야 <context:annotation-config />합니다. 즉 <context:annotation-config />, 등록 된 Bean에서만 작동합니다.

@Required는RequiredAnnotationBeanPostProcessor 처리 도구
@Autowired가 가능 AutowiredAnnotationBeanPostProcessor가공 공구

참고 : 주석 자체는 아무것도 할 일이 없으므로 핵심 프로세스를 담당하는 클래스 인 Processing Tool이 필요합니다 .


@Repository, @Service 및 @Controller는 @Component 이며 클래스 수준 대상으로합니다 .

<context:component-scan>패키지를 스캔하고 Bean을 찾아 등록하며에 의해 수행 된 작업이 포함됩니다 <context:annotation-config />.

XML을 주석으로 마이그레이션


답변

<context:annotation-config>태그는 Spring에게 @Autowired 주석을 포함하는 클래스의 종속성 요구 사항을 자동으로 해결하기 위해 코드베이스를 스캔하도록 지시합니다.

Spring 2.5는 또한 @Resource, @PostConstruct 및 @PreDestroy와 같은 JSR-250 주석에 대한 지원을 추가합니다. 이러한 주석을 사용하려면 특정 BeanPostProcessors를 Spring 컨테이너 내에 등록해야합니다. 항상 그렇듯이 개별 빈 정의로 등록 할 수 있지만 <context:annotation-config>스프링 구성에 태그를 포함시켜 암시 적으로 등록 할 수도 있습니다 .

Annotation Based Configuration 의 Spring 문서에서 발췌


Spring은 ‘스테레오 타입’클래스를 자동으로 감지하고 해당 BeanDefinition을 ApplicationContext에 등록하는 기능을 제공합니다.

org.springframework.stereotype의 javadoc에 따르면 :

스테레오 타입은 전체 아키텍처에서 유형 또는 메소드의 역할을 나타내는 주석입니다 (구현 레벨이 아닌 개념적 레벨). 예 : @Controller @Service @Repository 등. 도구 및 측면에서 사용하기위한 것입니다 (포인트 컷에 이상적인 대상 만들기).

이러한 ‘스테레오 타입’클래스를 자동 감지하려면 <context:component-scan>태그가 필요합니다.

<context:component-scan>태그는 또한 지정된 패키지 (및 모든 서브 패키지) 아래에 코드로 주사 가능한 빈을 스캔하도록 Spring에 지시합니다.