<text: anentation-config>和<text:组件扫描>之间的区别

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

从我所读到的,他们似乎处理不同的注释@Required@Autowired等vs@Component@Repository@Service等),但从我所读到的,他们注册相同的bean后处理器类。

更让我困惑的是,在<context:component-scan>上有一个annotation-config属性

有人能解释一下这些标签吗?什么是相似的,什么是不同的,一个被另一个取代,它们相互补充,我需要其中一个吗?两者兼而有之?

349543 次浏览

我发现了这个不错的摘要,其中注释被哪些声明拾取。通过研究它,你会发现<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/>具有CLASSPATH组件扫描和Java@Configuration功能。

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

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

详情请见:

<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

好的,这是预期的输出。但这是“老式”Spring。现在我们有注释,所以让我们使用它们来简化XML。

首先,让我们在beanA上自动装配bbbccc属性,如下所示:

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类,只选择了com.xxx包上的BC

为了解决这个问题,我还添加了另一个包:

<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:component-scan>,可以省略<context:annotation-config />),但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>工作。

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

Spring 2.5还增加了对JSR-250注解的支持,如@资源、@PostCon结构体和@普雷德斯特罗。使用这些注解还需要在Spring容器中注册某些BeanPost处理器。与往常一样,这些可以注册为单独的bean定义,但也可以通过在Spring配置中包含<context:annotation-config>标签来隐式注册。

基于注释的配置的弹簧留档


Spring提供了自动检测“构造型”类并将相应的BeanCust的功能注册到Application ationContext。

根据org.springframework.stereotype的javadoc:

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

要自动检测这种“原型”类,需要<context:component-scan>标签。

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

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

如果由于某种原因要避免这种默认bean定义的注册,那么这样做的方法是在组件扫描中指定一个额外的“注释配置”属性,如下所示:

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

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

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

<context:annotation-config />

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

在哪里作为

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

启用<context:annotation-config />可以做的一切,并添加使用原型,例如…@Component@Service@Repository。因此,您可以连接整个bean,而不仅仅局限于构造函数或属性!

Spring可以让你做两件事:

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

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

逃避手动XML配置的一个步骤是

2.自动发现
自动发现进一步简化了XML,甚至不需要在applicationContext.xml中添加<bean>标签。你只需使用以下注释之一标记特定的bean,Spring就会自动将标记的bean及其依赖连接到Spring容器中。注释如下:@刘振华@刘志强@陈子强@代码库。通过使用<context:component-scan>并指向基本包,Spring将自动发现组件并将组件连接到Spring容器中。


作为结论:

  • #使用EYZ0是为了能够使用 @自动生成注解
  • <context:component-scan />用于确定搜索 特定的bean和自动装配的尝试。
<context:annotation-config>

只有解析@Autowired@Qualifer注释,这就是全部,它是关于依赖注入的,还有其他注释做同样的工作,我认为@Inject如何,但所有关于通过注释解决DI。

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

  • XML:<bean>
  • @注释:@组件、@服务、@存储库、@控制器
  • JavaConfig:@Configuration,@Bean

现在与

<context:component-scan>

它做两件事:

  • 它扫描所有带注释的类 @组件、@服务、@存储库、@控制器和@配置并创建一个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><property>的任何内容,DI是通过@Autow的在他们自己的类中配置的。这意味着服务对他们的存储库组件使用@Autow的,存储库对JdbcTemboard、DataSource等使用@Autow的组件

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

尝试使用<context:component-scan base-package="..." annotation-config="false"/>,在您的配置中@服务@存储库@组件工作正常,但@已上线@资源@陈志立不起作用。

这意味着自动有线注释豆后处理器将不会被启用,Spring容器将不会处理自动装配注释。

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

这用于告诉容器我的包中有bean类扫描这些bean类。为了在bean上按容器扫描bean类,我们必须编写一个立体类型注释,如下所示。

@Component@Service@Repository@Controller

<context:annotation-config />

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

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

<context:annotation-config>

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

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

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

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

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


@已上线@必填目标财产水平,因此bean应该在使用这些注释之前在Spring IOC中注册。要启用这些注释,要么必须注册相应的bean,要么包含<context:annotation-config />。即<context:annotation-config />仅适用于注册的bean。

@陈志立启用RequiredAnnotationBeanPostProcessor处理工具
@自动启用AutowiredAnnotationBeanPostProcessor处理工具

备注:本身与注解无关,我们需要一个处理工具,它是下面的一个类,负责核心进程。


@存储库、@服务和@控制器是@组件,他们目标阶级水平

<context:component-scan>它扫描包并查找和注册bean,它包括<context:annotation-config />所做的工作。

将XML迁移到注释

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

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

它也在spring.io中描述

配置组件扫描指令以用于 @配置类。提供与Spring XML并行的支持 元素。

需要注意的一点是,如果您使用的是Spring Boot,则可以通过使用@SpringBootApplication注释来隐含@Configuration和@ComponentScan。