关于java:< context:annotation-config>之间的区别

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

我在学习Spring3,我似乎没有掌握背后的功能。

从我读到的内容来看,它们似乎处理不同的注释(@required,@autowired etc vs@component,@repository,@service etc),但从我读到的内容来看,它们注册了相同的bean后处理器类。

更让我困惑的是,上有一个annotation-config属性。

有人能给这些标签上点颜色吗?什么是相似的,什么是不同的,一个被另一个取代,它们互相完善,我需要它们中的一个吗,两者都需要?


用于激活已经在应用程序上下文中注册的bean中的注释(无论它们是用XML定义的还是通过包扫描定义的)。好的。

也可以做所做的事情,但是还扫描包以在应用程序上下文中查找和注册bean。好的。

我将用一些例子来说明不同/相似之处。好的。

让我们从ABC类型的三个bean的基本设置开始,将BC注入A。好的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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配置:好的。

1
2
3
4
5
6
<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>

加载上下文将生成以下输出:好的。

1
2
3
4
5
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 A上的bbbccc属性,如下所示:好的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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中删除以下行:好的。

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

我的XML现在简化为:好的。

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

当我加载上下文时,得到以下输出:好的。

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

好吧,这是错误的!发生了什么事?为什么我的属性没有自动连接?好的。

好吧,注释是一个很好的特性,但是它们本身什么也不做。他们只是做些注解。您需要一个处理工具来查找注释并对它们进行处理。好的。

去营救。这将激活它在同一个应用程序上下文中定义的bean上找到的注释的操作。好的。

如果我将XML更改为:好的。

1
2
3
4
<context:annotation-config />
<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A" />

当我加载应用程序上下文时,得到了正确的结果:好的。

1
2
3
4
5
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定义,并用注释替换它们:好的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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中,我们只保留以下内容:好的。

1
<context:annotation-config />

我们加载上下文,结果是…没有什么。不会创建bean,也不会自动连接bean。没有什么!好的。

这是因为,正如我在第一段中所说,只在应用程序上下文中注册的bean上工作。因为我删除了三个bean的XML配置,所以没有创建bean,也没有要处理的"目标"。好的。

但这对来说并不是问题,它可以扫描一个包来寻找"目标"来工作。让我们将XML配置的内容更改为以下条目:好的。

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

当我加载上下文时,得到以下输出:好的。

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

嗯…有东西不见了。为什么?好的。

如果你仔细观察这些类,A类有com.yyy包,但我在中指定要使用com.xxx包,所以这完全错过了我的A类,只得到了BC包,它们在com.xxx包上。好的。

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

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

现在我们得到了预期的结果:好的。

1
2
3
4
5
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中,在加载上下文之后我们会得到什么?好的。

1
2
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />

我们仍然得到正确的结果:好的。

1
2
3
4
5
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,仍然对所有注册的bean应用处理工具。在应用程序上下文中,甚至对于在XML中手动注册的A。好的。

但是如果我们有以下XML,我们会得到重复的bean吗,因为我们已经指定了?好的。

1
2
3
<context:annotation-config />
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />

不,没有重复,我们再次得到预期结果:好的。

1
2
3
4
5
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

这是因为两个标签都注册了相同的处理工具(如果指定了,则可以省略,但spring只负责运行它们一次。好的。

即使您自己多次注册处理工具,Spring仍然会确保它们只做一次魔术;此XML:好的。

1
2
3
4
5
6
7
<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" />

仍将生成以下结果:好的。

1
2
3
4
5
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的回复都能让你明白工作。好的。好啊。


我发现了这个很好的摘要,说明了哪些注释是由哪些声明获取的。通过研究,你会发现识别了识别的注释的超集,即:

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

正如你所看到的,EDCOX1,0,逻辑上扩展了EDCOX1,1,用类路径组件扫描和Java@配置特征。


弹簧允许你做两件事:

  • 豆子自动布线
  • 豆子的自动发现
  • 1。自动发电通常在applicationcontext.xml中定义bean,其他bean使用构造函数或setter方法。可以使用XML或注释连接bean。如果使用注释,则需要激活注释,并且必须添加applicationContext.xml中的。这将简化applicationContext.xml中标记的结构,因为您不必手动连接bean(构造函数或setter)。您可以使用@Autowire注释,bean将按类型连接。

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

    2。自动发现自动发现进一步简化了XML,从某种意义上说,您甚至不需要在applicationcontext.xml中添加标记。您只需使用以下注释之一标记特定的bean,Spring将自动将标记的bean及其依赖项连接到Spring容器中。注释如下:@controller、@service、@component、@repository。通过使用并指向基本组件,Spring将自动发现组件并将其连接到弹簧容器中。

    作为结论:

    • 为了能够使用@自动连线注释
    • 用于确定搜索具体的bean和自动布线的尝试。


    激活bean中的许多不同注释,不管它们是在XML中定义的还是通过组件扫描定义的。

    用于定义bean而不使用XML

    有关更多信息,请阅读:

    • 3.9。基于批注的容器配置
    • 3.10。类路径扫描和托管组件


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

    1
    <context:annotation-config />

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

    在哪里

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

    支持所能做的一切,除了使用模板,例如。@Component@Service@Repository。所以您可以连接整个bean,而不仅仅局限于构造函数或属性!.


    注:扫描已经注册和激活的弹簧配置在XML bean。

    豆+ 登记:

    autowired @ @和所需的目标应该是使物业水平指标在国际奥委会在Spring bean使用论文注释。一是要使论文注释include 豆或各自的寄存器。一个只读注册豆IU的作品。

    所需的处理工具提供RequiredAnnotationBeanPostProcessor@"autowired AutowiredAnnotationBeanPostProcessor处理工具使用

    注:标注本身没有什么我们需要做的,是加工工具,在A级,负责核心流程。

    "库"的服务和"控制器"组件是一流水平,和他们的目标。

    这包,找到它扫描和寄存器的豆,它包括由酒店工作。

    XML注释升级


    标记告诉spring扫描代码库以自动解决包含@autowired annotation的类的依赖性需求。

    Spring2.5还添加了对jsr-250注释的支持,如@resource、@postconstruct和@predstroy。使用这些注释还需要在Spring容器中注册某些beanPostProcessor。和往常一样,这些可以注册为单个bean定义,但也可以通过在Spring配置中包含标记隐式注册。

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

    Spring提供了自动检测"构造型"类并在applicationContext中注册相应的bean定义的功能。

    根据org.springframework.stereotype的javadoc:

    构造型是表示类型或方法在整个体系结构(在概念上,而不是在实现上)中的角色的注释。示例:@controller@service@repository等。这些是工具和方面使用的(成为切入点的理想目标)。

    为了自动检测这种"原型"类,需要标记。

    标签还告诉spring扫描指定包(及其所有子包)下的可注入bean代码。


    1
    <context:annotation-config>

    只解析@autowired和@qualifer注释,也就是说,关于依赖项注入,还有其他的注释做同样的工作,我想@inject是怎么做的,但是都将通过注释解析DI。

    注意,即使您已经声明了元素,您也必须声明您的类无论如何是一个bean,记住我们有三个可用的选项

    • xml:
    • @注释:@component,@service,@repository,@controller
    • javaconfig:@configuration,@bean

    现在用

    1
    <context:component-scan>

    它有两个功能:

    • 它扫描用注释的所有类@组件、@service、@repository、@controller和@configuration并创建bean
    • 它和的工作方式相同。

    因此,如果您申报,则不再需要申报

    这一切

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

    1
    2
    3
    4
    <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,与无关,DI通过@autowired在自己的类中配置。这意味着服务使用@autowired作为其存储库组件,存储库使用@autowired作为JDBCTemplate、数据源等组件。


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

    尝试使用,在您的配置@service,@repository,@component工作正常,但@autowired,@resource和@inject不工作。

    这意味着AutoWiredAnnotationBeanPostProcessor将不被启用,Spring容器将不处理AutoWiring注释。


    1
    2
    <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的annotation config元素设置为false

    总结:

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

    作为一个互补使用,你可以使用在@ComponentScan标注方式。

    它是在spring.io描述

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

    一个音符的事情,如果你使用Spring配置和启动,@ @ @诱发电可以springbootapplication隐含使用注释。


    你可以找到更多的信息在Spring上下文的架构文件。以下是在spring-context-4.3.xsd

    1
    <conxtext:annotation-config />
    1
    2
    3
    4
    5
    6
    7
    8
    9
    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.
    1
    <context:component-scan>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    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.

    这告诉我要跳一跳使用annotated豆豆与那些将有线通@Autowired标注,而declaring在Spring配置XML文件。

    本告诉Spring容器,在开始寻找那些annotated豆。这里的春天要搜索所有子包的库包。


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

    江户十一〔15〕、江户十一〔16〕、江户十一〔17〕、江户十一〔18〕。

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


    一个EDCOX1×0的自定义标签注册了一组bean定义,除了它的主要职责是扫描Java包和从类路径注册bean定义。

    如果出于某种原因,要避免注册默认be an定义,那么可以在组件扫描中指定一个附加的"annotation config"属性,方法如下:

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

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