[转载]Difference between <context:annotation-config> vs <context:component-scan>
在国外看到详细的说明一篇,非常浅显透彻。转给国内的筒子们:-)
原文标题:
Spring中的<context:annotation-config>与<context:component-scan>到底有什么不同?
原文出处:http://stackoverflow.com/a/7456501
<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).
<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.
Lets 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;
}
}
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
OK, this is the expected output. But this is "old style" Spring. Now we have annotations so lets use those to simplify the XML.
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;
}
}
This allows me to remove the following rows from the XML:
<property name="bbb" ref="bBean" />
<property name="ccc" ref="cBean" />
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.
<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.
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
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.
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;
}
}
While in the XML we only keep this:
<context:annotation-config />
We load the context and the result is... Nothing. No beans are created, no beans are autowired. Nothing!
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.
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?
If you look closelly 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
And that's it! Now you don't have XML definitions anymore, you have annotations.
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
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.
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
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.
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" />
will still generate the following result:
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
OK, that about raps it up.
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.
[转载]Difference between <context:annotation-config> vs <context:component-scan>的更多相关文章
- Mingyang.net:org.springframework.context.annotation.ConflictingBeanDefinitionException
org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean ...
- 【原创】大叔经验分享(16)Context namespace element 'component-scan' and its parser class [org.springframework.context.annotation.ComponentScanBeanDefinitionParser] are only available on JDK 1.5 and higher
今天尝试运行一个古老的工程,配置好之后编译通过,结果运行时报错: org.springframework.beans.factory.BeanDefinitionStoreException: Une ...
- spring 2.5.6 错误:Context namespace element 'component-scan' and its parser class [org.springframework.context.annotation.ComponentScanBeanDefinitionParser] are only available on JDK 1.5 and higher
在运行一个第三方公司交付的项目的时候, 出现: Caused by: java.lang.IllegalStateException: Context namespace element 'annot ...
- Context namespace element 'annotation-config' and its parser class [org.springframework.context.annotation.AnnotationConfigBeanDefinitionParser]
严重: Exception sending context initialized event to listener instance of class org.springframework.we ...
- class [org.springframework.context.annotation.ComponentScanBeanDefinitionParser] are only available on JDK 1.5 and higher
在搭建SSM项目时报了以下的错误: 06-Oct-2019 11:55:52.109 信息 [RMI TCP Connection(5)-127.0.0.1] org.apache.catalina. ...
- [org.springframework.context.annotation.ComponentScanBeanDefinitionParser] are only available on JDK 1.5 and higher 问题--MyEclipse设置JDK版本
org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML doc ...
- Context namespace element 'component-scan' and its parser class [org.springframework.context.annotation.ComponentScanBeanDefinitionParser] are only available on JDK 1.5 and higher
异常信息如下: 错误: Unexpected exception parsing XML document from class path resource [spring/applicationCo ...
- Context namespace element 'annotation-config' and its parser class [org.springframework.context.annotation.AnnotationConfigBeanDefinitionParser] are only available on JDK 1.5 and higher
Context namespace element 'annotation-config' and its parser class [org.springframework.context.anno ...
- Spring配置之context:annotation与、component-scan以及annotation-driven
spring boot帮助我们隐藏了大量的细节,有些配置spring boot都是开启的,因此当我们查看遗留项目使用spring时候遇见问题一定细心排查 <!-- context:annotat ...
随机推荐
- strust1与strust2,springmvc三者之间的区别?
strust1与struts2的区别 1.struts2是基于webWork的一个全新的框架,比struts1学习更方便 Struts2主要是改进了Struts1的servlet和acti ...
- 网络编程之addrinfo
addrinfo结构体定义如下: typedef struct addrinfo { int ai_flags;//指示在getaddrinfo函数中使用的选项的标志. int ai_family; ...
- 计算机网络中的帧封装(C实现)
这段时间开始复习计算机网络,看到帧封装这一节,结合以前的课程设计,就用C写了个帧封装的程序,说实话C学的确实不怎么样,实现的时候对于文件操作那部分查了好多资料,下面说说帧封装是啥情况. 学过计算机网络 ...
- php 总结第一篇(望大家补充!谢谢)
/* 数组的常用函数 * * 数组的排序函数 * sort() * rsort() * usort() * asort() * arsort() * uasort() * ...
- XSS跨站点脚本攻击
XSS攻击:跨站脚本攻击(Cross Site Scripting),为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS. 以下为Jav ...
- 【转载】Linux常用命令列表
原文地址:http://www.cnblogs.com/Javame/p/3968343.html 1 目录与文件操作 1.1 ls(初级) 使用权限:所有人 功能 : 显示指定工作目录下之内容(列出 ...
- Android 自定义View合集
自定义控件学习 https://github.com/GcsSloop/AndroidNote/tree/master/CustomView 小良自定义控件合集 https://github.com/ ...
- PropertyMetadata和UIPropertyMetadata的一点区别
使用UIPropertyMetadata写一个Brush的依赖属性. System.Windows.Application.Current.Dispatcher.BeginInvoke(new Act ...
- iOS ---不一样的NSLog打印(精准打印)
在iOS开发过程中,调试是很重要的过程,而除了各种断点调试(普通断点.条件断点.全局断点)之外,似乎NSLog是我们调试最常用的方法,当然,也是最简单朴素的寻debug方法. 在项目中,我们常使用的N ...
- CSS的Hack技术
主要是用来解决兼容性的特殊方法: IE都能识别*;标准浏览器(如FF)不能识别*: IE6能识别*,但不能识别 !important, IE7能识别*,也能识别!important,还有# FF不能识 ...