`
angelbill3
  • 浏览: 256937 次
  • 性别: Icon_minigender_2
  • 来自: 杭州
社区版块
存档分类
最新评论

【总结】<context:annotation-config> vs <context:component-scan>

 
阅读更多
Spring mvc3中的<context:annotation-config>和<context:component-scan>到底什么区别呢?平时是不是都在混用?今天看到一篇很不错的问答,解释的非常好。
原文地址如下:http://stackoverflow.com/questions/7414794/difference-between-contextannotation-config-vs-contextcomponent-scan

<context:annotation-config> 是用来激活已经在spring配置文件applicationContext.xml中注册过的bean(不管这个bean是在xml中定义的,还是包含在扫描包中的)。

<context:component-scan> 能做<context:annotation-config>所能做的事,除此之外,<context:component-scan>还能找到并注册在applicationContext.xml中配置的bean。

这么说很抽象,激活和注册的具体概念和区别又是什么呢?下面用一些小例子来说明个中的相同点和不同点。

现在有三个bean,A,B和C。类A中还注入了bean B和bean C。
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配置。

首先,在类A中,我们加入@Autowired标签来注入属性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中bean A中的property(属性)了。
<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


有没有发现,跟我们预想的不一样,中间出了错(在类A中没有成功设值bean B和bean C)。
注释确实是个很方便的技术,但到目前为止,它们还没有发挥出功效。它们如同待执行的任务一样,需要有一个好的工具去找到它们并且让它们能真正的启动起来。

标签<context:annotation-config>就是派来解救注解的。此话怎讲呢,这个标签可以找到那些在applicationContext中定义过的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配置才对。于是我们接着把定义bean的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被标签autowired激活了,这样的结果出乎意料。

就如同文章一开始提到的,标签<context:annotation-config />的作用对象权权是那些已经在applicationContext中定义过的bean(但并没有激活)。当我们把三个定义的bean的xml语句移掉后,标签<context:annotation-config />就找不到“目标”了。

但这个问题并不存在于标签<context:component-scan>中,标签<context:component-scan>可以扫描指定的java包,找到“目标”。(就算bean没有在xml中定义也没关系)。
我们将xml中的配置修改如下:
<context:component-scan base-package="com.xxx" />


启动项目,得到了如下的输出:
creating bean B: com.xxx.B@1be0f0a
creating bean C: com.xxx.C@80d1ff


好像少了类A的加载,为什么呢?
如果我们仔细观察这些类,会发现类A的java包是com.yyy,并不是标签<context:component-scan>中定义的com.xxx,所以这才是为什么漏掉整个A类的加载的原因。

为了修补这个bug,我们将base-package修改如下:
<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


至此,我们完成了符合注释风格的代码。

题外话,如果我们执意将base-package只定义为com.xxx,那有没有办法做到对类A的加载呢?那必须定义bean A。
<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并没有包含在扫描的java包中,标签<context:component-scan>还是会找到所有在applicationContext.xml中定义的其它所有bean(就像手动定义的beanA)。

那么,当我们在一个xml中同时配置标签<context:annotation-config />和<context:component-scan>,会发生什么呢?如下的配置会让类A重复加载吗?
<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 />会被忽略。

甚至当你定义同一个bean很多次,Spring总是能确保它们只会被加载一次,如下:
<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






分享到:
评论

相关推荐

    异常解决:错误:namespace element 'annotation-config' … on JDK 1.5 and higher

    2. **XML配置问题**:确保你的Spring配置文件(如`applicationContext.xml`)正确包含了`&lt;context:component-scan&gt;`或`&lt;context:annotation-config&gt;`元素,它们是启用注解配置的关键。 3. **编译器设置**:检查你的...

    Spring注解详解

    &lt;context:annotation-config /&gt; ``` 这将隐式地向 Spring 容器注册 `AutowiredAnnotationBeanPostProcessor`、`CommonAnnotationBeanPostProcessor`、`PersistenceAnnotationBeanPostProcessor` 和 `...

    集成springmvc spring hibernate的配置

    &lt;context:annotation-config /&gt; &lt;context:component-scan base-package="com.mvc.*"&gt; &lt;context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" /&gt; &lt;/context:component...

    15、spring 配置以及使用 1

    在这个主题中,我们将深入探讨`&lt;context:annotation-config&gt;`与`&lt;context:component-scan&gt;`的区别,事务管理器的配置,以及Spring开发环境的选择和数据源的配置。 1. `&lt;context:annotation-config&gt;`和`&lt;context:...

    spring mvc

    2. `&lt;context:component-scan&gt;`: - 这个元素告诉Spring扫描指定包及其子包,寻找带有`@Controller`注解的类,并将它们作为bean进行管理。 3. `&lt;mvc:annotation-driven&gt;`(通常也会包含,但此处未提供): - 这个...

    使用Spring2.5的Autowired实现注释型的IOC

    在上面的配置文件中,我们使用了 `&lt;context:annotation-config/&gt;` 和 `&lt;context:component-scan base-package="testspring.main"/&gt;` 两个标签。 `&lt;context:annotation-config/&gt;` 用于启用注释型的 IOC,而 `&lt;context...

    struts2.3+hibernate3.6+spring3.1整合的纯xml配置的小项目

    &lt;context:component-scan base-package="org.whvcse"&gt;&lt;/context:component-scan&gt; &lt;tx:annotation-driven transaction-manager="txManager" /&gt; &lt;!-- &lt;aop:config&gt; &lt;aop:pointcut id="defaultServiceOperation" ...

    JSP 中spring事务配置详解.docx

    在这个配置中,`&lt;context:component-scan&gt;`用于自动扫描指定包下的类,发现`@Repository`、`@Service`等注解并进行注册。`&lt;context:annotation-config&gt;`启用对注解的处理,使得我们可以使用`@Transactional`注解来...

    Spring的Annotation配置相关讲义

    `&lt;context:component-scan&gt;`元素用于指定需要扫描的包,这样Spring会自动发现这些包下标记了如`@Component`、`@Service`、`@Repository`等注解的类,并将它们注册为Bean。 接着,我们看DAO层的配置。使用`@...

    第十章 Spring 配置元信息(Configuration Metadata)1

    此外,`&lt;context:annotation-config&gt;`和`&lt;context:component-scan&gt;`分别用于启用注解驱动和扫描特定包下的@Component注解。 6. **基于Java注解装载配置元信息**:Java配置类通过`@Configuration`、`@Bean`等注解...

    spring注解使用

    在上面的配置文件中,我们使用了 `&lt;context:annotation-config/&gt;` 和 `&lt;context:component-scan&gt;` 两个元素。`&lt;context:annotation-config/&gt;` 元素用于激活注解驱动的 Bean, `&lt;context:component-scan&gt;` 元素用于...

    关于Spring的spring-beans-xsd和tx-xsd aop-xsd等

    它包括了如`&lt;context:component-scan&gt;`、`&lt;context:annotation-config&gt;`等元素,使得我们可以方便地启用注解驱动的配置和组件扫描,发现并自动装配带有特定注解的类。此外,它还支持消息源、AOP代理、事件监听等特性...

    spring包扫描配置的项目

    在Spring中,包扫描是通过`&lt;context:component-scan&gt;`标签实现的,该标签位于XML配置文件中。这个标签告诉Spring去指定的包及其子包下查找标记为`@Component`、`@Service`、`@Repository`和`@Controller`的类,这些...

    SSM框架笔记

    - `&lt;context:component-scan&gt;`: 扫描指定包下的组件。 - `&lt;context:annotation-config&gt;`: 启用注解驱动。 - `&lt;context:property-placeholder&gt;`: 引用外部属性文件。 - `&lt;mvc:resources&gt;`: 配置静态资源路径。 - `&lt;tx...

    ssm 框架配置

    &lt;/context:component-scan&gt; ``` 这里配置了对`Controller`、`Service`和`Repository`注解的扫描,从而实现了对相应组件的自动装配。 #### 三、数据类型转换配置 在SSM框架中,数据类型转换主要是为了将前端传来的...

    Spring3注解介绍.docx

    3. **组件扫描**:通过`&lt;context:component-scan&gt;`元素,不仅注册注解处理器,还可以扫描指定包下的类,自动发现和处理注解: ```xml &lt;context:component-scan base-package="com.yourpackage"/&gt; ``` `base-...

    spring-framework-3.2.0.RC2-schema.zip

    `context`命名空间下的 `&lt;context:component-scan&gt;`、`&lt;context:property-placeholder&gt;`等元素,用于扫描组件、加载外部属性文件,增强了Spring的应用范围和灵活性。 "cache"模块则提供了缓存抽象,支持如 EhCache...

    spring注解详细介绍

    `&lt;context:annotation-config/&gt;` 和 `&lt;context:component-scan base-package="需要实现注入的类所在包"/&gt;` 是两个重要的 XML 配置元素,它们用于开启注解支持和指定扫描的包范围。 - `&lt;context:annotation-config/&gt;...

Global site tag (gtag.js) - Google Analytics