<context:annotation-config>
用于激活已经在应用程序上下文中注册的bean中的注释(无论它们是使用XML定义还是通过包扫描定义的)。
<context:component-scan>
还可以做什么<context:annotation-config>
呢,但<context:component-scan>
还可以扫描软件包以在应用程序上下文中查找并注册bean。
我将使用一些示例来显示差异/相似之处。
让我们用型的三种豆基本设置开始A
,B
并且C
,与B
和C
被注入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的bbb
和ccc
属性,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
嗯...有些东西丢失了。为什么?
如果您仔细看一下这些类,该类A
具有程序包,com.yyy
但是我已经在<context:component-scan>
use程序包中指定了该程序包,com.xxx
因此这完全错过了我的A
课程,只进行了学习,B
而C
这些内容都放在了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定义,而有了注释。
作为最后一个示例,保留带注释的类A
,B
并将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中手动注册的。
但是,如果我们具有以下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>
工作。