applicationContext.xml中<context:annotation-config> 和 <context:component-scan>的区别

本文对比了<context:annotation-config>与<context:component-scan>的区别及用法,阐述了如何利用注解进行依赖注入,并讨论了不同配置方式的效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Difference between <context:annotation-config> vs <context:component-scan>

 

<context:annotation-config> 是用于激活那些已经在spring容器里注册过的bean(无论是通过xml的方式还是通过package sanning的方式)上面的注解。

<context:component-scan>除了具有<context:annotation-config>的功能之外,<context:component-scan>还可以在指定的package下扫描以及注册javabean 。

 

下面我们通过例子来详细查看他们的区别,

有三个class   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; 
  }
}

 

 

在applicationContext.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>

 

加载applicationContext.xml配置文件,将得到下面的结果:

 

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, 这个结果没什么好说的,就是完全通过xml的方式,不过太过时了,下面通过注解的方式来简化我们的xml配置文件

首先,我们使用autowire的方式将对象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;
  }
}
 

 

 

然后,我们就可以从applicationContext.xml中移除下面的配置

 

<property name="bbb" ref="bBean"/><property name="ccc" ref="cBean"/>

 

移除之后,我们的applicationContext.xml配置文件就简化为下面的样子了

 

<bean id="bBean"class="com.xxx.B"/><bean id="cBean"class="com.xxx.C"/><bean id="aBean"class="com.yyy.A"/>

 

当我们加载applicationContext.xml配置文件之后,将得到下面的结果:

 

creating bean B: com.xxx.B@5e5a50
creating bean C: com.xxx.C@54a328
creating bean A: com.yyy.A@a3d4cf

 

OK, 结果是错误的的,究竟是因为什么呢?为什么我们的属性没有被注入进去呢?

是因为注解本身并不能够做任何事情,它们只是最基本的组成部分,我们需要能够处理这些注解的处理工具来处理这些注解

这就是<context:annotation-config> 所做的事情

我们将applicationContext.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"/>

 

当我们加载applicationContext.xml配置文件之后,将得到下面的结果:

 

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, 结果正确了

但是如果我们将代码作如下修改:

 

 

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;
  }
}
 

 

 

 

applicationContext.xml配置文件修改为:

 

<context:annotation-config />

 

当我们加载applicationContext.xml配置文件之后,却没有任何输出,这是为什么呢?

那是因为<context:annotation-config />仅能够在已经在已经注册过的bean上面起作用。对于没有在spring容器中注册的bean,它并不能执行任何操作。

但是不用担心,<context:component-scan>除了具有<context:annotation-config />的功能之外,还具有自动将带有@component,@service,@Repository等注解的对象注册到spring容器中的功能。

我们将applicationContext.xml配置文件作如下修改:

 

<context:component-scan base-package="com.xxx"/>

 

当我们加载applicationContext.xml的时候,会得到下面的结果:

 

creating bean B: com.xxx.B@1be0f0a
creating bean C: com.xxx.C@80d1ff

 

这是什么原因呢?

是因为我们仅仅扫描了com.xxx包及其子包的类,而class  A是在com.yyy包下,所以就扫描不到了

下面我们在applicationContext.xml中把com.yyy也加入进来:

 

<context:component-scan base-package="com.xxx"/>

<context:component-scan base-package="com.xxx,com.yyy"/>
然后加载applicationContext.xml就会得到下面的结果:
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

 

哇,结果正确啦 !

回头看下我们的applicationContext.xml文件,已经简化为:

 

<context:component-scan base-package="com.xxx"/>

<context:component-scan base-package="com.xxx,com.yyy"/>

 

了。

 

那如果我们在applicationContext.xml手动加上下面的配置,也就是说既在applicationContext.xml中手动的注册了A的实例对象,同时,通过component-scan去扫描并注册B,C的对象

 

<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

 

虽然class  A并不是通过扫描的方式注册到容器中的 ,但是<context:component-scan> 所产生的的处理那些注解的处理器工具,会处理所有绑定到容器上面的bean,不管是通过xml手动注册的还是通过scanning扫描注册的。

那么,如果我们通过下面的方式呢?我们既配置了<context:annotation-config />,又配置了<context:component-scan base-package="com.xxx" />,它们都具有处理在容器中注册的bean里面的注解的功能。会不会出现重复注入的情况呢?

 

<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>同时存在的时候,前者会被忽略。也就是那些@autowire,@resource等注入注解只会被注入一次

哪怕是你手动的注册了多个处理器,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

 

 

ERROR [main] org.springframework.web.context.ContextLoader Context initialization failed org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from ServletContext resource [/WEB-INF/applicationContext.xml]; nested exception is org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'commentService' for bean class [com.xhxy.eshop.service.impl.mybatis.CommentServiceImpl] conflicts with existing, non-compatible bean definition of same name and class [com.xhxy.eshop.service.impl.jdbc.CommentServiceImpl] at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:417) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:338) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:310) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:196) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:232) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:203) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:125) ~[spring-web-5.3.15.jar:5.3.15] at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:94) ~[spring-web-5.3.15.jar:5.3.15] at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshab
最新发布
03-25
&lt;think>好的,我现在需要解决用户在Spring框架中遇到的ConflictingBeanDefinitionException异常,特别是由CommentServiceImpl类引起的问题。用户提到了mybatis、jdbcapplicationContext.xml,可能需要检查相关配置。首先,我需要回忆这个异常通常发生的原因。 ConflictingBeanDefinitionException通常是因为Spring容器中存在多个相同名称或类型的Bean定义。用户的问题中涉及到'commentService',说明可能有多个Bean被命名为commentService,或者在组件扫描时发现了重复的类。 接下来,我需要考虑用户提供的引用内容。引用[3]中提到了CommentService接口CommentServiceImpl实现类。用户可能在实现类上没有正确使用@Service注解,或者没有指定Bean的名称,导致Spring在扫描时创建了多个实例。另外,引用[1][2]提到了applicationContext.xmlMyBatis的配置,可能存在XML配置文件中重复定义了commentService的Bean。 可能的解决步骤包括: 1. 检查CommentServiceImpl类是否使用了@Service注解,并确保没有在其他地方(如XML配置)重复定义该Bean。 2. 检查组件扫描的包路径是否正确,避免重复扫描导致多次注册。 3. 查看MyBatis的Mapper扫描配置,确保没有误将Service类作为Mapper接口处理。 4. 检查是否有通过@Bean注解或其他方式手动创建了commentService的实例,导致冲突。 还需要考虑用户是否在applicationContext.xml中同时使用了注解XML配置来定义同一个Bean,这也会导致冲突。此外,如果用户使用了@MapperScan,需要确认扫描的包路径是否只包含Mapper接口,而不包含Service类,避免MyBatisSpring同时创建Bean。 可能的解决方案包括统一使用注解或XML配置,避免混合使用;检查并修正组件扫描的范围;使用@Qualifier指定Bean名称等。另外,查看异常堆栈信息中的具体位置,帮助定位问题根源。&lt;/think>### 解决Spring中ConflictingBeanDefinitionException的步骤 #### 1. 确认Bean名称冲突来源 `ConflictingBeanDefinitionException`表明存在重复的Bean定义。针对`commentService`冲突: - **检查XML配置**:在`applicationContext.xml`中搜索`&lt;bean id="commentService">`,确认是否手动定义了同名Bean[^1]。 - **检查注解声明**:确保`CommentServiceImpl`类**仅使用一种方式声明Bean**(如`@Service("commentService")`或XML配置),避免混合使用注解XML重复定义。 #### 2. 规范组件扫描范围 - **检查组件扫描路径**:若使用`@ComponentScan`或XML的`&lt;context:component-scan&gt;`,确保未重复扫描同一包。例如: ```xml &lt;!-- applicationContext.xml --> &lt;context:component-scan base-package="com.aaa.service,com.aaa.dao"/> &lt;!-- 避免包含已通过其他方式注册的包 --> ``` - **检查MyBatis Mapper扫描**:`@MapperScan`应仅扫描Mapper接口包,例如`@MapperScan("com.aaa.dao")`,若扫描范围包含Service类会导致冲突[^2]。 #### 3. 检查Bean命名策略 - **显式指定Bean名称**:在`CommentServiceImpl`类上添加`@Service("commentService")`,覆盖默认命名规则: ```java @Service("commentService") // 显式定义Bean名称 public class CommentServiceImpl implements CommentService {...} ``` - **检查接口实现类命名**:若存在多个`CommentService`实现类(如测试类或旧版本残留),需排除无关类。 #### 4. 验证MyBatis代理冲突 - **Mapper接口与Service类隔离**:确保Mapper接口(如`CommentMapper`)与Service类(如`CommentServiceImpl`)不在同一包下,避免MyBatis误将Service类作为Mapper代理[^4]。 #### 5. 检查依赖注入方式 - **字段注入与构造器注入**:避免在XML注解中同时注入同一Bean。例如: ```xml &lt;!-- 错误示例:XML中定义Bean --> &lt;bean id="commentService" class="com.aaa.service.CommentServiceImpl"/> ``` ```java // 错误示例:同时使用注解声明 @Service public class CommentServiceImpl {...} ``` #### 6. 清理编译结果并重启 - 执行Maven/Gradle的`clean`任务,删除`target/`或`build/`目录,重新编译项目。IDE缓存可能导致旧Bean定义残留。 --- ### 示例修正代码 **CommentServiceImpl.java** ```java @Service("commentService") // 显式命名 public class CommentServiceImpl implements CommentService { @Autowired private CommentMapper commentMapper; // 确保Mapper已被正确扫描 // 实现方法... } ``` **applicationContext.xml**(如有) ```xml &lt;!-- 移除手动定义的commentService Bean --> &lt;!-- 保留组件扫描配置,但范围不包含Service层 --> &lt;context:component-scan base-package="com.aaa.dao"/> ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值