首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 ><上下文:注释-config>和<context:component-scan>之间的区别

<上下文:注释-config>和<context:component-scan>之间的区别
EN

Stack Overflow用户
提问于 2011-09-14 10:28:33
回答 15查看 349.5K关注 0票数 721

我正在学习Spring 3,我似乎没有掌握<context:annotation-config><context:component-scan>背后的功能。

从我所读到的内容来看,它们似乎处理不同的注释(@Required@Autowired等与@Component@Repository@Service等),但从我所读到的内容来看,它们也注册了相同的bean后处理器类。

更让我困惑的是,在annotation-config上有一个<context:component-scan>属性。

有人能弄清楚这些标签吗?什么是相似的,什么是不同的,一个被另一个取代,他们互相完善,我需要他们中的一个,两者都是吗?

EN

回答 15

Stack Overflow用户

发布于 2011-09-17 17:16:46

<context:annotation-config>用于激活已经在应用程序上下文中注册的bean中的注释(不管它们是用XML定义的还是通过包扫描定义的)。

<context:component-scan>也可以做<context:annotation-config>做的事情,但是<context:component-scan>也扫描包以在应用程序上下文中查找和注册bean。

我将用一些例子来说明它们的区别和相似之处。

让我们从ABC类型的三个bean的基本设置开始,将BC注入A

代码语言:javascript
复制
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配置:

代码语言:javascript
复制
<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>

加载上下文会产生以下输出:

代码语言:javascript
复制
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。

首先,让我们自动创建bean bbbccc属性,如下所示:

代码语言:javascript
复制
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中删除以下行:

代码语言:javascript
复制
<property name="bbb" ref="bBean" />
<property name="ccc" ref="cBean" />

我的XML现在简化为:

代码语言:javascript
复制
<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A" />

当我加载上下文时,我得到以下输出:

代码语言:javascript
复制
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更改为以下内容:

代码语言:javascript
复制
<context:annotation-config />
<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A" />

当我加载应用程序上下文时,我得到了正确的结果:

代码语言:javascript
复制
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定义并将它们全部替换为注释:

代码语言:javascript
复制
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中,我们只保留以下内容:

代码语言:javascript
复制
<context:annotation-config />

我们加载上下文,结果是..。没什么。没有创建bean,没有bean是自动生成的。没什么!

这是因为,正如我在第一段中所说的,<context:annotation-config />只对应用程序上下文中注册的bean起作用。因为我删除了三个bean的XML,所以没有创建bean,而且<context:annotation-config />没有任何“目标”可以处理。

但是对于<context:component-scan>来说,这并不是一个问题,因为它可以扫描一个包来寻找要工作的“目标”。让我们将XML配置的内容更改为以下条目:

代码语言:javascript
复制
<context:component-scan base-package="com.xxx" />

当我加载上下文时,我得到以下输出:

代码语言:javascript
复制
creating bean B: com.xxx.B@1be0f0a
creating bean C: com.xxx.C@80d1ff

嗯..。有东西不见了。为什么?

如果仔细观察这些类,类A有包com.yyy,但是我在<context:component-scan>中指定要使用包com.xxx,所以这完全忽略了com.yyy类,只获取了com.xxx包上的BC

为了解决这个问题,我还添加了另一个包:

代码语言:javascript
复制
<context:component-scan base-package="com.xxx,com.yyy" />

现在我们得到了预期的结果:

代码语言:javascript
复制
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定义了,而是有了注释。

最后一个例子是,保留带注释的类ABC,并将以下内容添加到XML中,加载上下文之后我们将得到什么?

代码语言:javascript
复制
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />

我们仍然得到了正确的结果:

代码语言:javascript
复制
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

即使A类的bean不是通过扫描获得的,<context:component-scan>仍然在应用程序上下文中注册的所有bean上应用处理工具,甚至对于手动在XML中注册的A也是如此。

但是,如果我们有下面的XML,我们会得到重复的bean吗,因为我们同时指定了<context:annotation-config /><context:component-scan>

代码语言:javascript
复制
<context:annotation-config />
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />

不,没有重复,我们再次得到了预期的结果:

代码语言:javascript
复制
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:

代码语言:javascript
复制
<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" />

仍将生成以下结果:

代码语言:javascript
复制
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和@Sean的回复都能让您了解<context:annotation-config><context:component-scan>是如何工作的。

票数 1.5K
EN

Stack Overflow用户

发布于 2011-09-14 10:39:59

我找到了一个很好的摘要,其中的注释是由哪个声明获取的。通过研究它,您将发现<context:component-scan/>识别了一个由<context:annotation-config/>识别的超集注释,即:

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

正如您所看到的,<context:component-scan/>逻辑上扩展了具有CLASSPATH组件扫描和Java@配置特性的 <context:annotation-config/>

票数 170
EN

Stack Overflow用户

发布于 2013-08-12 02:29:14

春天允许你做两件事:

  1. 豆类自动脱毛
  2. 豆类的自动发现

1.自动装配

通常在applicationContext.xml中,定义bean和其他bean使用构造函数或setter方法进行连接。您可以使用XML或注释连接bean。如果使用注释,则需要激活注释,并且必须在<context:annotation-config />中添加applicationContext.xml。这将简化applicationContext.xml标记的结构,因为您不必手动连接bean(构造函数或setter)。您可以使用@Autowire注释,bean将按类型连接。

转义手动XML配置的前进一步是

2.自动发现

自动发现进一步简化了XML,这意味着您甚至不需要在applicationContext.xml中添加太多的XML标记。只需使用以下注释之一标记特定的bean,Spring将自动将标记的bean及其依赖项连接到Spring容器中。注释如下:@Controller、@Service、@Component、@Repository。通过使用<context:component-scan>和指向基本包,Spring将自动发现组件并将其连接到Spring容器中。

作为结论:

  • 使用<context:annotation-config />是为了能够使用@Autowired注释
  • <context:component-scan />用于确定特定bean的搜索和自动连接的尝试。
票数 99
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7414794

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档