<context:annotation-config> 之间的区别和 <context:component-scan> [英] Difference between <context:annotation-config> and <context:component-scan>

查看:28
本文介绍了<context:annotation-config> 之间的区别和 <context:component-scan>的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在学习 Spring 3,但我似乎没有掌握 .

I'm learning Spring 3 and I don't seem to grasp the functionality behind <context:annotation-config> and <context:component-scan>.

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

From what I've read they seem to handle different annotations (@Required, @Autowired etc vs @Component, @Repository, @Service etc), but also from what I've read they register the same bean post processor classes.

更让我困惑的是, 上有一个 annotation-config attribute.

To confuse me even more, there is an annotation-config attribute on <context:component-scan>.

有人可以解释一下这些标签吗?有什么相似,有什么不同,一个取代另一个,它们相互补充,我需要它们中的一个,两者都需要吗?

Can someone shed some light on these tags? What's similar, what's different, is one superseded by the other, they complete each other, do I need one of them, both?

推荐答案

用于激活已注册在应用程序上下文中的 bean 中的注解(无论它们是否是用 XML 或包扫描定义的).

<context:annotation-config> is used to activate annotations in beans already registered in the application context (no matter if they were defined with XML or by package scanning).

也可以做 能做的事情,但 还扫描包以在应用程序上下文中查找和注册 bean.

<context:component-scan> can also do what <context:annotation-config> does but <context:component-scan> also scans packages to find and register beans within the application context.

我会用一些例子来说明不同点/相似点.

I'll use some examples to show the differences/similarities.

让我们从 ABC 类型的三个 bean 的基本设置开始,其中 BC 被注入到 A 中.

Let's start with a basic setup of three beans of type A, B and C, with B and C being injected into 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 配置:

With the following XML configuration :

<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>

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

Loading the context produces the following output:

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.

OK, this is the expected output. But this is "old style" Spring. Now we have annotations so let's use those to simplify the XML.

首先,让 bbbccc 属性自动连接到 bean A 上,如下所示:

First, lets autowire the bbb and ccc properties on bean A like so:

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 中删除以下行:

This allows me to remove the following rows from the XML:

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

我的 XML 现在简化为:

My XML is now simplified to this:

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

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

When I load the context I get the following output:

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

好吧,这是错误的!发生了什么?为什么我的属性没有自动装配?

OK, this is wrong! What happened? Why aren't my properties autowired?

嗯,注释是一个很好的功能,但它们本身什么都不做.他们只是注释东西.您需要一个处理工具来查找注释并对其进行处理.

Well, annotations are a nice feature but by themselves, they do nothing whatsoever. They just annotate stuff. You need a processing tool to find the annotations and do something with them.

来救援.这将激活它在定义自身的同一应用程序上下文中定义的 bean 上找到的注释的操作.

<context:annotation-config> to the rescue. This activates the actions for the annotations that it finds on the beans defined in the same application context where itself is defined.

如果我将我的 XML 更改为:

If I change my XML to this:

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

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

when I load the application context I get the proper result:

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.

OK, this is nice, but I've removed two rows from the XML and added one. That's not a very big difference. The idea with annotations is that it's supposed to remove the XML.

所以让我们删除 XML 定义并用注释替换它们:

So let's remove the XML definitions and replace them all with annotations:

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 中我们只保留这个:

While in the XML we only keep this:

<context:annotation-config />

我们加载上下文,结果是……什么都没有.没有创建 bean,也没有自动装配 bean.没什么!

We load the context and the result is... Nothing. No beans are created, no beans are autowired. Nothing!

那是因为,正如我在第一段中所说,<context:annotation-config/> 仅适用于在应用程序上下文中注册的 bean.因为我删除了三个 bean 的 XML 配置,所以没有创建 bean,并且 没有目标".继续工作.

That's because, as I said in the first paragraph, the <context:annotation-config /> only works on beans registered within the application context. Because I removed the XML configuration for the three beans there is no bean created and <context:annotation-config /> has no "targets" to work on.

但这对于 来说不是问题,它可以扫描目标"包.工作.让我们将 XML 配置的内容更改为以下条目:

But that won't be a problem for <context:component-scan> which can scan a package for "targets" to work on. Let's change the content of the XML config into the following entry:

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

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

When I load the context I get the following output:

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

嗯……少了点什么.为什么?

Hmmmm... something is missing. Why?

如果你仔细观察类,类 A 有包 com.yyy 但我已经在 中指定了 使用包 com.xxx 所以这完全错过了我的 A 类,只拿起 BC 位于 com.xxx 包中.

If you look closely at the classes, class A has package com.yyy but I've specified in the <context:component-scan> to use package com.xxx so this completely missed my A class and only picked up B and C which are on the com.xxx package.

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

To fix this, I add this other package also:

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

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

and now we get the expected result:

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 定义,您有注释.

And that's it! Now you don't have XML definitions anymore, you have annotations.

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

As a final example, keeping the annotated classes A, B and C and adding the following to the XML, what will we get after loading the context?

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

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

We still get the correct result:

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不是通过扫描获得的,处理工具仍然被应用在所有注册的bean上在应用程序上下文中,即使对于在 XML 中手动注册的 A 也是如此.

Even if the bean for class A isn't obtained by scanning, the processing tools are still applied by <context:component-scan> on all beans registered in the application context, even for A which was manually registered in the XML.

但是如果我们有以下 XML 会怎样,因为我们已经指定了 <context:annotation-config/><context:component-扫描>?

But what if we have the following XML, will we get duplicated beans because we've specified both <context:annotation-config /> and <context:component-scan>?

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

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

No, no duplications, We again get the expected result:

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

那是因为两个标签注册了相同的处理工具( 如果 是指定)但 Spring 只负责运行它们一次.

That's because both tags register the same processing tools (<context:annotation-config /> can be omitted if <context:component-scan> is specified) but Spring takes care of running them only once.

即使您自己多次注册处理工具,Spring 仍会确保它们只发挥一次魔力;这个 XML:

Even if you register the processing tools yourself multiple times, Spring will still make sure they do their magic only once; this 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 的回复是您了解如何 工作.

I hope this information along with the responses from @Tomasz Nurkiewicz and @Sean Patrick Floyd are all you need to understand how <context:annotation-config> and <context:component-scan> work.

这篇关于&lt;context:annotation-config&gt; 之间的区别和 &lt;context:component-scan&gt;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆