<context:annotation-config> vs <context:component-scan>之间的区别
我正在学习Spring 3,而我似乎并没有把握<context:annotation-config>
和<context:component-scan>
背后的function。
从我读过的,他们似乎处理不同的注释(@Required,@Autowired等与@Component,@Repository,@Service等),但也从我读了他们注册相同的豆后处理器类。
为了让我更加困惑,在<context:component-scan>
上有一个annotation-config
属性。
有人可以对这些标签有所了解吗? 什么是相似的,什么是不同的,是一个被另一个取代的,它们是完整的,我需要其中之一吗?
<context:annotation-config>
用于激活已在应用程序上下文中注册的bean中的注释(无论它们是使用XML还是通过包扫描来定义的)。
<context:component-scan>
也可以执行<context:annotation-config>
所做的事情,但是<context:component-scan>
也扫描软件包以在应用程序上下文中查找和注册bean。
我将用一些例子来说明不同之处/相似之处。
让我们从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; } }
使用以下XMLconfiguration:
<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。
首先,让autowire bean上的bbb
和ccc
属性如下所示:
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
好的,这是错误的! 发生了什么? 为什么不是我的属性自动assembly?
那么,注释是一个很好的function,但它们本身什么都不做。 他们只是注释的东西。 您需要一个处理工具来查找注释并与他们做一些事情。
<context:annotation-config>
来拯救。 这激活了它在自己定义的同一个应用程序上下文中定义的bean上find的注释的动作。
如果我将我的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定义,并用注释replace它们:
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被创build,没有bean被自动assembly。 没有!
这是因为,正如我在第一段中所说的, <context:annotation-config />
只适用于在应用程序上下文中注册的bean。 因为我删除了三个bean的XMLconfiguration,所以没有创buildbean,并且<context:annotation-config />
没有“目标”。
但是对于<context:component-scan>
这不会是一个问题,它可以扫描一个打包的“目标”进行工作。 我们将XMLconfiguration的内容更改为以下条目:
<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
类,只拾取了B
和C
在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定义了,你有注解。
作为最后一个例子,保留带注释的类A
, B
和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应用,即使是在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:component-scan/>
可以识别由<context:annotation-config/>
识别的注释的超集,即:
-
@Repository
@Endpoint
,@Repository
@Controller
,@Repository
,@Controller
@Endpoint
,@Controller
@Endpoint
-
@Import
@DependsOn
,@Import
@DependsOn
,@Import
@DependsOn
,@Import
@DependsOn
,@Import
@DependsOn
,@Import
@DependsOn
,@Import
@DependsOn
,@Import
@DependsOn
,@Import
@DependsOn
,@Import
@ImportResource
正如您可以看到<context:component-scan/>
<context:annotation-config/>
使用CLASSPATH组件扫描和Java @Configurationfunction从逻辑上扩展了 <context:annotation-config/>
。
Spring允许你做两件事:
- 豆类自动assembly
- 豆的自动发现
1.自动assembly
通常在applicationContext.xml中定义bean和其他bean使用构造函数或setter方法进行连线。 您可以使用XML或注释来连接bean。 如果使用注释,则需要激活注释,并且必须在applicationContext.xml中添加<context:annotation-config />
。 这将简化applicationContext.xml中标签的结构,因为您不必手动连接bean(构造函数或setter)。 您可以使用@Autowire
注释,并按types连接bean。
转义手动XMLconfiguration的一步是
2.自动发现
自动发现正在进一步简化XML,因为您甚至不需要在applicationContext.xml中添加<bean>
标记。 您只需使用以下其中一种注释标记特定的bean,Spring将自动将标记的bean及其依赖项连接到Spring容器中。 注释如下: @Controller , @ Service , @ Component , @Repository 。 通过使用<context:component-scan>
并指向基础包,Spring将自动发现并将组件连接到Spring容器。
作为结论:
- 为了能够使用@Autowired注解,使用
<context:annotation-config />
-
<context:component-scan />
用于确定search特定的bean并尝试自动assembly。
<context:annotation-config>
激活bean中的许多不同注释,不pipe它们是以XML还是通过组件扫描来定义的。
<context:component-scan>
用于定义bean而不使用XML
欲了解更多信息,请阅读:
- 3.9。 基于注解的容器configuration
- 3.10。 类path扫描和托pipe组件
两者的区别真的很简单!
<context:annotation-config />
使您能够使用仅限于Bean的属性和构造函数的注释。
在哪里
<context:component-scan base-package="org.package"/>
启用<context:annotation-config />
可以做的所有事情,另外还可以使用@Component
型例如.. @Component
@Service
, @Repository
, @Service
@Repository
。 所以你可以连接整个bean,而不仅限于构造函数或属性!
<context:annotation-config>
标签告诉Spring扫描代码库以自动解决包含@Autowired注释的类的依赖性需求。
Spring 2.5还增加了对诸如@Resource,@PostConstruct和@ PreDestroy之类的JSR-250注释的支持。使用这些注解还要求在Spring容器中注册某些BeanPostProcessors。 与往常一样,这些可以注册为单独的bean定义,但是它们也可以通过在springconfiguration中包含<context:annotation-config>
标签来隐式注册。
Spring 基础注释configuration文档
Spring提供了自动检测'stereotyped'类的能力,并在ApplicationContext中注册了相应的BeanDefinitions。
根据org.springframework.stereotype的 javadoc:
定型是注释,表示types或方法在整个架构中(在概念层面而不是实施层面)的angular色。 示例:@Controller @Service @Repository等。这些是供工具和方面使用的(作为切入点的理想目标)。
为了自动检测这样的“原型”类,需要<context:component-scan>
标签。
<context:component-scan>
标签还告诉Spring在指定的包(及其所有子包)下扫描注射bean的代码。
TL;博士
<context:annotation-config>
:在spring config xml中扫描和激活已经注册的bean的注释。
<context:component-scan>
: Bean注册+ <context:annotation-config>
@Autowired和@Required是target属性级别,所以bean在使用这些注释之前应该在spring IOC中注册。 要启用这些注释,必须注册相应的bean或者包含<context:annotation-config />
。 即<context:annotation-config />
只能用于注册的bean。
@Required启用RequiredAnnotationBeanPostProcessor
处理工具
@Autowired启用AutowiredAnnotationBeanPostProcessor
处理工具
注意:注释本身无关,我们需要一个处理工具 ,它是一个下面的类,负责核心进程。
@Repository,@Service和@Controller是@Component ,它们是以类级别为目标的 。
<context:component-scan>
它扫描包并查找和注册bean,它包含<context:annotation-config />
完成的工作。
<context:annotation-config>
只parsing@Autowired和@Qualifer注解,这就是所有关于dependency injection ,还有其他注释做同样的工作,我想怎么@Inject,但所有通过注释来解决DI。
请注意,即使您已经声明了<context:annotation-config>
元素, 您也必须声明您的类如何使用Bean,请记住,我们有三个可用的选项
- XML:
<bean>
- @Annotations:@Component,@Service,@Repository,@Controller
- JavaConfig:@Bean
现在用
<context:component-scan>
它有两件事情:
- 它扫描所有用@Component,@Service,@Repository,@Controller和@Configuration注解的类并创build一个Bean
- 它在
<context:annotation-config>
执行相同的工作。
因此,如果声明<context:component-scan>
,则不再需要声明<context:annotation-config>
。
就这样
例如,常见的情况是通过XML声明一个bean,然后通过注释parsingDI
<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是通过@Autowired在自己的类中configuration的。 这意味着服务使用@Autowired来存储它们的Repositories组件,而Repositories使用@Autowired作为JdbcTemplate,DataSource等.components
<context:component-scan /> implicitly enables <context:annotation-config/>
尝试使用<context:component-scan base-package="..." annotation-config="false"/>
,在你的configuration@Service,@Repository,@Component工作正常,但@ Autowired,@Resource和@Inject不起作用。
这意味着AutowiredAnnotationBeanPostProcessor将不会被启用,Spring容器将不会处理Autowiring注解。
<context:annotation-config/> <!-- is used to activate the annotation for beans --> <context:component-scan base-package="xyMyClass" /> <!-- 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元素context:component-scan
为false
。
总结:
<context:annotation-config/> <!-- activates the annotations --> <context:component-scan base-package="xyMyClass" /> <!-- activates the annotations + register the beans by looking inside the base-package -->
一个<context:component-scan/>
定制标记除了负责扫描java包和从类path注册bean定义之外,还注册了一组相同的bean定义。
如果由于某种原因要避免这种默认bean定义的注册,那么这样做的方法是在组件扫描中指定一个额外的“annotation-config”属性,如下所示:
<context:component-scan basePackages="" annotation-config="false"/>
参考: http : //www.java-allandsundry.com/2012/12/contextcomponent-scan-contextannotation.html
<context:component-scan base-package="package name" />
:
这是用来告诉容器,我的包中有bean类来扫描这些bean类。 为了在容器的顶部扫描bean类,我们必须编写一个如下的立体声types注释。
@Component
@Service
, @Repository
@Controller
, @Repository
, @Controller
<context:annotation-config />
:
如果我们不想在XML中显式地写bean标记,那么容器如何知道bean中是否有自动连线。 这可以通过使用@Autowired
注释。 我们必须通知容器,在我的bean中有context:annotation-config
自动布线context:annotation-config
。
背景:注解configuration:
这告诉Spring,我是使用Annoatted bean作为spring bean,并通过@Autowired注释来连线,而不是在spring config xml文件中声明。
上下文:component-scan base-package =“com.test …”:这告诉Spring容器,从哪里开始search那些带注释的bean。 在这里spring将search所有的分包