java - <context :annotation-config> and <context:component-scan> 之间的区别

标签 java spring configuration annotations spring-3

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

从我读过的内容来看,它们似乎处理不同的注释( @Required@Autowired 等 vs @Component@Repository@Service 等),而且从我读过的内容来看,它们注册了相同的 bean 帖子处理器类。

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

有人可以对这些标签有所了解吗?什么相似,什么不同,一个被另一个取代,它们相互补充,我需要它们中的一个吗?

最佳答案

<context:annotation-config>用于激活已在应用程序上下文中注册的 bean 中的注释(无论它们是用 XML 定义的还是通过包扫描定义的)。<context:component-scan>还可以做什么<context:annotation-config>但是<context:component-scan>还扫描包以在应用程序上下文中查找和注册 bean。
我将使用一些示例来展示差异/相似之处。
让我们从三个类型为 A 的 bean 的基本设置开始。 , BC , 与 BC被注入(inject) 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
好的,这是预期的输出。但这是“老式” Spring 。现在我们有了注释,所以让我们使用它们来简化 XML。
首先,让我们 Autowiring bbbccc bean 的属性 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
好吧,这是错误的!发生了什么?为什么我的属性没有 Autowiring ?
嗯,注释是一个很好的功能,但它们本身什么都不做。他们只是注释东西。您需要一个处理工具来查找注释并对其进行处理。<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 />
我们加载上下文,结果是......没有。没有创建 bean,也没有 Autowiring 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
嗯……少了点什么。为什么?
如果你仔细观察这些类,类 A有包com.yyy但我已经在 <context:component-scan> 中指定了使用包com.xxx所以这完全错过了我的 A类(class),才接了BCcom.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 , BC并将以下内容添加到 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
即使是类(class)的bean A不是通过扫描获得的,处理工具仍然由<context:component-scan>应用在所有注册的 bean 上
在应用程序上下文中,即使对于 A这是在 XML 中手动注册的。
但是如果我们有下面的 XML,我们会得到重复的 bean,因为我们同时指定了 <context:annotation-config /><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>工作。

关于java - <context :annotation-config> and <context:component-scan> 之间的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7414794/

相关文章:

spring - 使用@RequestParam 时出错但用作参数 Java/Spring 时不出错

java - 多个应用程序之间共享事务

xml - 您如何全局设置 Jackson 以忽略 Spring 中的未知属性?

hadoop 2.2.0 java.lang.Thread.run 容器启动异常(Thread.java :744)

java - 为什么当我将嵌套的静态 Fragment 类声明为私有(private)时会产生错误?

java - 如何使用Junit测试对象是否被修改?

xml - Eclipse 导入 conf .xml 文件

python - matplotlib 找不到配置文件 matplotlibrc

java - XCode 与 Java : how to send and receive files

java - 如何使 JOptionPane 对话框显示为任务栏上的任务?