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

从我读到的内容来看,它们似乎处理不同的注释(@Required@Autowired等与@Component@Repository (例如@Service等),但从我的阅读中也可以看到它们注册了相同的bean后处理器类。 />有人可以说明这些标签吗?相似之处,不同之处是,一个被另一个取代,它们彼此完成,我是否需要其中一个?

评论

techidiocy.com/annotation-config-vs-component-scan-spring-core此处是出色的解释

总结:尽可能使用component-scan。

#1 楼

<context:annotation-config>用于激活已在应用程序上下文中注册的bean中的注释(无论它们是使用XML定义还是通过包扫描定义的。)<context:component-scan>也可以执行<context:annotation-config>的操作,但是<context:component-scan>还将包扫描到在应用程序上下文中查找并注册bean。

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

让我们开始基本配置三个类型为ABC的bean,然后将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


OK ,这是预期的输出。但这是“旧风格”的春天。现在我们有了注释,因此让我们使用它们来简化XML。首先,让我们自动装配bean bbb上的cccA属性,如下所示:

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定义了,有了注释。作为最后的示例,保留带注释的类ABC并将以下内容添加到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 Nurkiewicz和@Sean Patrick Floyd的回复,以了解
<context:annotation-config><context:component-scan>的工作方式。

评论


引用:“如果指定了,则可以省略”。那么为什么要使用注释配置?为什么存在?

– CodeClimber
2013年1月10日17:22



好答案!简明扼要的说明不像简短的示例。一口气理解了整个事情。

–吉吉
13年6月18日在15:35

希望您写了整个Spring手册!关于与Spring Framework混淆相关的任何事情的最好的解释。谢谢。

–eskalera
13年11月21日在9:30

如此简单而出色的解释。除了得到答案之外,我还学会了很好的讲方法的方法:)

–阿米尔·艾尔(Amir Al)
2014年11月11日13:02

您的写作风格对于初学者来说很容易理解。希望您能写一本有关基本Spring的书。我保证买。

–emeraldhieu
2014年11月7日10:04

#2 楼

我发现了这个不错的摘要,说明了哪些声明由哪些声明组成。通过研究,您将发现<context:component-scan/>可以识别<context:annotation-config/>识别的注释的超集,即:



@Component@Service@Repository@Controller@Endpoint


@Configuration@Bean@Lazy@Scope@Order@Primary@Profile@DependsOn@Import@ImportResource


您可以看到<context:component-scan/>逻辑扩展了<context:annotation-config/>并使用CLASS扩展了q4312079q Java @Configuration功能。

评论


@Tomasz链接关闭:(

– Anand Rockzz
2015年12月2日,7:37

#3 楼

Spring允许您做两件事:


自动装配beans
自动发现beans

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

转义手动XML配置的第一步是

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


作为结论:



<context:annotation-config />用于能够使用
@Autowired注释

<context:component-scan />用于确定特定于Bean的搜索和自动装配尝试。
/>

评论


是否可以以某种方式使用组件扫描而不使用注释配置?

–科雷·图吉(Koray Tugay)
2015年12月3日在21:51

在context:注解配置标记中使用注解配置=“ false”。

–萨拉
18/12/12在4:05

#4 楼

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

3.10。类路径扫描和托管组件


评论


你能进一步解释一下吗?如果使用,我将无法使用XML覆盖bean定义吗?

–user938214097
2011-09-14 10:46

@ user938214097您可以使用XML或通过带有组件扫描的注释来定义bean

–塞恩·帕特里克·弗洛伊德(Sean Patrick Floyd)
2011年9月14日上午10:47

使用是否足够?如果不使用,我是否会松动某些东西?

–user938214097
2011年9月14日上午10:50

@Tomasz似乎已经回答了

–塞恩·帕特里克·弗洛伊德(Sean Patrick Floyd)
2011年9月14日上午10:52

#5 楼

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

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


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

@必需启用RequiredAnnotationBeanPostProcessor处理工具@Autowired启用AutowiredAnnotationBeanPostProcessor处理工具

注意:注释本身无能为力,我们需要处理工具,这是底层的类,负责核心流程。


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

<context:component-scan>扫描软件包并查找并注册Bean,其中包括<context:annotation-config />完成的工作。

将XML迁移到注释

#6 楼

两者之间的区别真的很简单!。

<context:annotation-config /> 


使您能够使用仅限于连接属性和构造器的注解!。

在哪里

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


启用<context:annotation-config />可以做的所有事情,另外还使用构造型,例如@Component@Service@Repository。因此,您可以连接整个bean,而不仅限于构造函数或属性!

#7 楼

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

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

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


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

根据org.springframework.stereotype的javadoc:

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

要自动检测此类“定型”类,则需要<context:component-scan>标签。

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

#8 楼

<context:annotation-config>
仅解析@Autowired@Qualifer批注,仅此而已,它与依赖注入有关。还有其他批注执行相同的工作,我认为@Inject的工作方式相同,但所有这些都将通过批注解决DI。

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


XML: <bean>
@Annotations:@ Component,@ Service,@ Repository,@ Controller
JavaConfig:@Configuration,@Bean

现在带有

<context:component-scan>


它有两件事:


它扫描所有带有
@ Component,@ Service,@ Repository,@ Controller和@Configuration注释的类。创建Bean
<context:annotation-config>的作用相同。 />
常见的情况是例如声明onl ya bean通过XML并通过注释解析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,与<context:component-scan><context:annotation-config>无关,DI是自己配置的通过@Autowired类。这意味着服务将@Autowired用于其存储库组件,而存储库将@Autowired用于JdbcTemplate,DataSource等。.components

评论


精湛的解释谢谢。 @Manuel乔丹

– Bals
19年6月3日在12:20

#9 楼

<context:component-scan /> implicitly enables <context:annotation-config/>


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

此意味着将不会启用AutowiredAnnotationBeanPostProcessor,并且Spring容器将不会处理Autowiring注释。

评论


这帮助我理解隐式启用;它扫描Bean定义以及所需的注入。我尝试使用注解-config =“ false”,除非我使用进行了显式设置,否则注入不会起作用。最后我的理解比以前更好了!

–́CuriousMind
16年7月30日在13:55



#10 楼

<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-scan的注释配置元素设置为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 -->


#11 楼

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

这是用来告诉容器我的包中有Bean类,请扫描这些Bean类。为了按容器在Bean顶部扫描Bean类,我们必须编写一个立体声类型注释,如下所示。



如果我们不想用XML显式编写bean标签,那么容器如何知道bean中是否存在自动接线。通过使用@Component批注,这是可能的。我们必须通过@Service通知容器我的bean中有自动接线。

#12 楼

一个<context:component-scan/>自定义标记除了注册Java包并从类路径注册Bean定义的主要职责外,还注册了与Bean相同的Bean定义集。避免使用bean定义,方法是在component-scan中指定一个附加的“ annotation-config”属性,方法是:

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


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

#13 楼

<context:annotation-config>

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

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

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

#14 楼

您可以在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.


#15 楼

作为补充,您可以使用@ComponentScan以注释方式使用<context:component-scan>

还将在spring.io中进行描述。


配置组件扫描指令以与
@Configuration类一起使用。提供与Spring XML的
元素并行的支持。要注意的一件事,如果您使用的是Spring Boot,则可以使用@SpringBootApplication隐含@Configuration和@ComponentScan。注解。