715

我正在学习 Spring 3,但我似乎没有掌握 and 背后的<context:annotation-config>功能<context:component-scan>

从我读到的内容来看,它们似乎处理不同的注释@Required, @Autowiredetc vs @Component, @Repository,@Service等),但从我读到的内容来看,它们注册了相同的bean 后处理器类。

更让我困惑的annotation-config <context:component-scan>.

有人可以对这些标签有所了解吗?什么相似,什么不同,一个被另一个取代,它们相互补充,我需要它们中的一个,两者都需要吗?

4

15 回答 15

1466

<context:annotation-config>用于激活已在应用程序上下文中注册的 bean 中的注释(无论它们是使用 XML 定义的还是通过包扫描定义的)。

<context:component-scan>还可以执行该<context:annotation-config>操作,<context:component-scan>还可以扫描包以在应用程序上下文中查找和注册 bean。

我将使用一些示例来展示差异/相似之处。

让我们从三个 bean 类型的基本设置开始AB并且C,BC被注入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 上的bbbccc属性,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>使用包中指定了,com.xxx所以这完全错过了我的A课,只捡起了BC上的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 定义,而是有了注释。

作为最后一个示例,保留带注释的类AB并将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,会因为我们同时指定了<context:annotation-config />和 而得到重复的 bean<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 Patrick Floyd 的回复是您了解如何 工作<context:annotation-config><context:component-scan>工作所需的全部内容。

于 2011-09-17T17:16:46.937 回答
170

我发现了这个很好的总结,哪些注释被哪些声明拾取。通过研究它,你会发现它<context:component-scan/>识别了一个由 识别的注释的超集<context:annotation-config/>,即:

  • @Component, @Service, @Repository, @Controller,@Endpoint
  • @Configuration, @Bean, @Lazy, @Scope, @Order, @Primary, @Profile, @DependsOn, @Import,@ImportResource

正如您所见,通过 CLASSPATH 组件扫描和 Java @Configuration 功能在<context:component-scan/>逻辑上进行了扩展。 <context:annotation-config/>

于 2011-09-14T10:39:59.553 回答
99

Spring允许你做两件事:

  1. bean 的自动装配
  2. 豆类的自动发现

1. 自动装配
通常在applicationContext.xml中定义 bean,其他 bean 使用构造函数或 setter 方法进行装配。您可以使用 XML 或注释连接 bean。如果您使用注解,则需要激活注解并且必须添加 applicationContext.xml<context:annotation-config />。这将简化applicationContext.xml中标记的结构,因为您不必手动连接 bean(构造函数或设置器)。您可以使用注释,bean 将按类型连接。@Autowire

转义手动 XML 配置的一个步骤是

2. 自动
发现 自动 发现进一步简化了 XML,从某种意义上说,您甚至不需要在applicationContext.xml<bean>中添加标签。您只需使用以下注释之一标记特定 bean,Spring 将自动将标记的 bean 及其依赖项连接到 Spring 容器中。注释如下: @Controller@ Service 、 @ Component@Repository。通过使用和指向基础包,Spring 将自动发现组件并将其连接到 Spring 容器中。<context:component-scan>


作为结论:

  • <context:annotation-config />用于为了能够使用 @Autowired注解
  • <context:component-scan />用于确定特定 bean 的搜索和自动装配的尝试。
于 2013-08-12T02:29:14.123 回答
39

<context:annotation-config>激活 bean 中的许多不同注解,无论它们是在 XML 中定义还是通过组件扫描定义的。

<context:component-scan>用于在不使用 XML 的情况下定义 bean

如需更多信息,请阅读:

于 2011-09-14T10:41:53.577 回答
34

<context:annotation-config>:在 spring config xml 中扫描和激活已注册 bean 的注释。

<context:component-scan>:豆注册 +<context:annotation-config>


@Autowired 和 @Required目标属性级别,因此 bean 应该在使用这些注释之前在 Spring IOC 中注册。要启用这些注释,要么必须注册相应的 bean,要么包含<context:annotation-config />. 即<context:annotation-config />仅适用于注册的bean。

@Required启用 RequiredAnnotationBeanPostProcessor 处理工具
@Autowired启用 AutowiredAnnotationBeanPostProcessor处理工具

注:注解本身无关,我们需要一个Processing Tool,它是下面的一个类,负责核心流程。


@Repository、@Service 和 @Controller 是 @Component,它们以类级别为目标

<context:component-scan>它扫描包并查找和注册 bean,它包括<context:annotation-config />.

将 XML 迁移到注解

于 2016-01-02T02:22:35.857 回答
31

两者的区别真的很简单!

<context:annotation-config /> 

使您能够使用仅限于连接 bean 的属性和构造函数的注释!

然而

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

启用所有<context:annotation-config />可以做的事情,除了使用刻板印象,例如.. @Component, @Service, @Repository. 因此,您可以连接整个 bean,而不仅限于构造函数或属性!

于 2013-08-01T22:29:04.967 回答
18
<context:annotation-config>

解析@Autowired@Qualifer注解,仅此而已,关于依赖注入,还有其他注解做同样的工作,我认为如何@Inject,但都是通过注解来解决DI。

请注意,即使您已经声明了<context:annotation-config>元素,您也必须将您的类声明为 Bean,记住我们有三个可用选项

  • XML:<bean>
  • @注解:@Component、@Service、@Repository、@Controller
  • JavaConfig:@Configuration,@Bean

现在有了

<context:component-scan>

它做了两件事:

  • 它扫描所有使用@Component、@Service、@Repository、@Controller 和@Configuration 注释的类并创建一个Bean
  • 它做同样的工作<context:annotation-config>

因此,如果你声明<context:component-scan>了,也没有必要再声明<context:annotation-config>了。

就这样

一个常见的场景是,例如通过 XML 仅声明一个 bean,并通过注释解析 DI,例如

<bean id="serviceBeanA" class="com.something.CarServiceImpl" />
<bean id="serviceBeanB" class="com.something.PersonServiceImpl" />
<bean id="repositoryBeanA" class="com.something.CarRepository" />
<bean id="repositoryBeanB" class="com.something.PersonRepository" />

我们只声明了 bean,没有关于<constructor-arg>and <property>,DI 是通过@Autowired 在它们自己的类中配置的。这意味着服务将@Autowired 用于其存储库组件,而存储库将@Autowired 用于JdbcTemplate、DataSource 等。组件

于 2014-06-06T13:28:57.823 回答
15

<context:annotation-config>标签告诉 Spring 扫描代码库以自动解决包含 @Autowired 注释的类的依赖要求。

Spring 2.5 还增加了对 JSR-250 注释的支持,例如 @Resource、@PostConstruct 和 @PreDestroy。使用这些注释还需要在 Spring 容器中注册某些 BeanPostProcessor。与往常一样,这些可以注册为单独的 bean 定义,但也可以通过<context:annotation-config>在 spring 配置中包含标签来隐式注册。

取自基于注释的配置的 Spring 文档


Spring 提供了自动检测“原型”类并使用 ApplicationContext 注册相应 BeanDefinition 的能力。

根据org.springframework.stereotype的javadoc :

刻板印象是表示类型或方法在整体架构中的角色的注释(在概念级别,而不是实现级别)。示例:@Controller @Service @Repository 等。这些旨在供工具和方面使用(成为切入点的理想目标)。

要自动检测此类“刻板印象”类,<context:component-scan>需要标记。

<context:component-scan>标签还告诉 Spring 扫描指定包(及其所有子包)下的可注入 bean 的代码。

于 2012-08-31T09:08:20.050 回答
7
<context:component-scan /> implicitly enables <context:annotation-config/>

尝试<context:component-scan base-package="..." annotation-config="false"/>在您的配置中使用@Service、@Repository、@Component工作正常,但@Autowired、@Resource@Inject不起作用。

这意味着AutowiredAnnotationBeanPostProcessor将不会被启用,Spring 容器将不会处理自动装配注解。

于 2014-10-03T18:30:04.230 回答
5
<context:annotation-config/> <!-- is used to activate the annotation for beans -->
<context:component-scan base-package="x.y.MyClass" /> <!-- is for the Spring IOC container to look for the beans in the base package. -->

另一个需要注意的重点是context:component-scan隐式调用context:annotation-config来激活 bean 上的注释。好吧,如果您不想context:component-scan为您隐式激活注释,您可以继续设置context:component-scanto的 annotation-config 元素false

总结一下:

<context:annotation-config/> <!-- activates the annotations --> 
<context:component-scan base-package="x.y.MyClass" /> <!-- activates the annotations + register the beans by looking inside the base-package -->
于 2015-04-10T16:05:19.560 回答
1

<context:component-scan base-package="package name" />

这用于告诉容器我的包中有 bean 类扫描那些 bean 类。为了通过 bean 顶部的容器扫描 bean 类,我们必须编写如下的立体类型注释之一。

@Component, @Service, @Repository,@Controller

<context:annotation-config />

如果我们不想在 XML 中显式编写 bean 标记,那么容器如何知道 bean 中是否有自动连接。这可以通过使用@Autowired注释来实现。我们必须通知容器我的 bean 中有自动接线context:annotation-config

于 2015-01-29T01:35:15.157 回答
0

<context:component-scan/>定义标记注册与 所完成的相同的 bean 定义集,除了它的主要职责是扫描 java 包和从类路径注册 bean 定义。

如果出于某种原因要避免这种默认 bean 定义的注册,那么这样做的方法是在组件扫描中指定一个附加的“annotation-config”属性,这样:

<context:component-scan basePackages="" annotation-config="false"/>

参考: http ://www.java-allandsundry.com/2012/12/contextcomponent-scan-contextannotation.html

于 2013-06-15T06:56:20.203 回答
0

As a complementary, you can use @ComponentScan to use <context:component-scan> in annotation way.

It's also described at spring.io

Configures component scanning directives for use with @Configuration classes. Provides support parallel with Spring XML's element.

One thing to note, if you're using Spring Boot, the @Configuration and @ComponentScan can be implied by using @SpringBootApplication annotation.

于 2019-03-15T09:16:07.210 回答
0

您可以在 spring 上下文模式文件中找到更多信息。以下是在 spring-context-4.3.xsd 中

<conxtext:annotation-config />
Activates various annotations to be detected in bean classes: Spring's @Required and
@Autowired, as well as JSR 250's @PostConstruct, @PreDestroy and @Resource (if available),
JAX-WS's @WebServiceRef (if available), EJB 3's @EJB (if available), and JPA's
@PersistenceContext and @PersistenceUnit (if available). Alternatively, you may
choose to activate the individual BeanPostProcessors for those annotations.

Note: This tag does not activate processing of Spring's @Transactional or EJB 3's
@TransactionAttribute annotation. Consider the use of the <tx:annotation-driven>
tag for that purpose.
<context:component-scan>
Scans the classpath for annotated components that will be auto-registered as
Spring beans. By default, the Spring-provided @Component, @Repository, @Service, @Controller, @RestController, @ControllerAdvice, and @Configuration stereotypes    will be detected.

Note: This tag implies the effects of the 'annotation-config' tag, activating @Required,
@Autowired, @PostConstruct, @PreDestroy, @Resource, @PersistenceContext and @PersistenceUnit
annotations in the component classes, which is usually desired for autodetected components
(without external configuration). Turn off the 'annotation-config' attribute to deactivate
this default behavior, for example in order to use custom BeanPostProcessor definitions
for handling those annotations.

Note: You may use placeholders in package paths, but only resolved against system
properties (analogous to resource paths). A component scan results in new bean definitions
being registered; Spring's PropertySourcesPlaceholderConfigurer will apply to those bean
definitions just like to regular bean definitions, but it won't apply to the component
scan settings themselves.
于 2019-02-01T08:22:49.713 回答
0

<context:annotation-config>

这告诉 Spring 我将使用带注释的 bean 作为 spring bean,并且这些将通过@Autowired注释连接,而不是在 spring config xml 文件中声明。

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

这告诉 Spring 容器,从哪里开始搜索那些带注释的 bean。这里spring会搜索基础包的所有子包。

于 2015-12-30T11:16:43.920 回答