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

我正在学习春天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。

我将用一些例子来说明差异/相似之处。

让我们用型的三种豆基本设置开始AB并且C,与BC被注入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。

首先,让我们在bean上自动装配bbbccc属性,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 />

我们加载上下文,结果是……没什么。没有创建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班,只有拿起BC它们的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定义,您有注释。

作为最后一个例子,保留带注释的类AB并将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

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

但是,如果我们有以下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帕特里克·弗洛伊德的响应沿着这条信息,都是你需要了解如何 <context:annotation-config><context:component-scan>工作。

添加评论

友情链接:蝴蝶教程