<context:annotation-config> 之间的区别和 <context:component-scan> [英] Difference between <context:annotation-config> and <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.
让我们从 A
、B
和 C
类型的三个 bean 的基本设置开始,其中 B
和 C
被注入到 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.
首先,让 bbb
和 ccc
属性自动连接到 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
类,只拿起 B
和 C
位于 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.
作为最后一个示例,保留带注释的类 A
、B
和 C
并将以下内容添加到 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.
这篇关于<context:annotation-config> 之间的区别和 <context:component-scan>的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!