我正在学习Spring 3,我似乎没有掌握<context:annotation-config>和<context:component-scan>背后的功能。
从我所读到的内容来看,它们似乎处理不同的注释(@Required、@Autowired等与@Component、@Repository、@Service等),但从我所读到的内容来看,它们也注册了相同的bean后处理器类。
更让我困惑的是,在annotation-config上有一个<context:component-scan>属性。
有人能弄清楚这些标签吗?什么是相似的,什么是不同的,一个被另一个取代,他们互相完善,我需要他们中的一个,两者都是吗?
发布于 2011-09-17 17:16:46
<context:annotation-config>用于激活已经在应用程序上下文中注册的bean中的注释(不管它们是用XML定义的还是通过包扫描定义的)。
<context:component-scan>也可以做<context:annotation-config>做的事情,但是<context:component-scan>也扫描包以在应用程序上下文中查找和注册bean。
我将用一些例子来说明它们的区别和相似之处。
让我们从A、B和C类型的三个bean的基本设置开始,将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属性,如下所示:
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>中指定要使用包com.xxx,所以这完全忽略了com.yyy类,只获取了com.xxx包上的B和C。
为了解决这个问题,我还添加了另一个包:
<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上应用处理工具,甚至对于手动在XML中注册的A也是如此。
但是,如果我们有下面的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和@Sean的回复都能让您了解<context:annotation-config>和<context:component-scan>是如何工作的。
发布于 2011-09-14 10:39:59
我找到了一个很好的摘要,其中的注释是由哪个声明获取的。通过研究它,您将发现<context:component-scan/>识别了一个由<context:annotation-config/>识别的超集注释,即:
@Component,@Service,@Repository,@Controller,@Endpoint@Configuration,@Bean,@Lazy,@Scope,@Order,@Primary,@Profile,@DependsOn,@Import,@ImportResource正如您所看到的,<context:component-scan/>逻辑上扩展了具有CLASSPATH组件扫描和Java@配置特性的 <context:annotation-config/>。
发布于 2013-08-12 02:29:14
春天允许你做两件事:
1.自动装配
通常在applicationContext.xml中,定义bean和其他bean使用构造函数或setter方法进行连接。您可以使用XML或注释连接bean。如果使用注释,则需要激活注释,并且必须在<context:annotation-config />中添加applicationContext.xml。这将简化applicationContext.xml标记的结构,因为您不必手动连接bean(构造函数或setter)。您可以使用@Autowire注释,bean将按类型连接。
转义手动XML配置的前进一步是
2.自动发现
自动发现进一步简化了XML,这意味着您甚至不需要在applicationContext.xml中添加太多的XML标记。只需使用以下注释之一标记特定的bean,Spring将自动将标记的bean及其依赖项连接到Spring容器中。注释如下:@Controller、@Service、@Component、@Repository。通过使用<context:component-scan>和指向基本包,Spring将自动发现组件并将其连接到Spring容器中。
作为结论:
<context:annotation-config />是为了能够使用@Autowired注释<context:component-scan />用于确定特定bean的搜索和自动连接的尝试。https://stackoverflow.com/questions/7414794
复制相似问题