我正在学习Spring 3,我似乎没有掌握<context:annotation-config>
和<context:component-scan>
背后的功能。
根据我的阅读,他们似乎处理不同的注释(@ Required,@ Autowired etc vs @Component,@ Repository,@ Service等),但也从我读过的内容中注册了相同的bean后处理器类。
为了让我更加困惑,annotation-config
上有一个<context:component-scan>
属性。
有人可以对这些标签有所了解吗?什么是相似的,什么是不同的,一个被另一个取代,它们相互完成,我需要其中一个,两者都有吗?
<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;
}
}
使用以下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 bbb
上自动装配ccc
和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>
来说,这不会是一个问题,因为<context:component-scan base-package="com.xxx" />
可以扫描包裹中的“目标”。让我们将XML配置的内容更改为以下条目:
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
现在我们得到了预期的结果:
A
就是这样!现在您不再拥有XML定义,您有注释。
作为最后一个例子,保留带注释的类B
,C
和<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />
并将以下内容添加到XML中,加载上下文后我们会得到什么?
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
即使没有通过扫描获得类<context:component-scan>
的bean,A
仍然会在应用程序上下文中注册的所有bean上应用处理工具,即使对于在XML中手动注册的<context:annotation-config />
也是如此。
但是,如果我们有以下XML,我们会得到重复的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>
,则可以省略<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" />
)但是Spring只负责运行它们一次。
即使你自己多次注册处理工具,Spring仍然会确保他们只做一次魔术;这个XML:
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
仍会产生以下结果:
<context:annotation-config>
好吧,关于包装它。
我希望这些信息以及@Tomasz Nurkiewicz和@Sean Patrick Floyd的回复都是你需要了解<context:component-scan>
和summary的工作方式。
context:component-scan
需要注意的另一个要点是,context:annotation-config
隐式调用context:component-scan
来激活bean上的注释。好吧,如果您不希望context:component-scan
为您隐式激活注释,您可以继续将false
的annotation-config元素设置为<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:component-scan/>
除了扫描java包和从类路径注册bean定义的主要职责之外,<context:component-scan basePackages="" annotation-config="false"/>
自定义标记注册了相同的bean定义集。
如果由于某种原因要避免默认bean定义的注册,那么这样做的方法是在component-scan中指定一个额外的“annotation-config”属性,这样:
http://www.java-allandsundry.com/2012/12/contextcomponent-scan-contextannotation.html
参考:<context:component-scan base-package="package name" />
@Component
:
这用于告诉容器我的包中有bean类扫描这些bean类。为了在bean的顶部按容器扫描bean类,我们必须编写一个立体类型注释,如下所示。
@Service
,@Repository
,@Controller
,<context:annotation-config />
@Autowired
:
如果我们不想在XML中显式地编写bean标记,那么容器如何知道bean中是否存在自动连线。这可以通过使用context:annotation-config
注释来实现。我们必须通知容器,我的豆子里有<context:annotation-config>
的自动接线。
@Autowired
:
这告诉Spring我将使用Annotated bean作为spring bean,那些将通过<context:component-scan base-package="com.test...">
注释连接,而不是在spring config xml文件中声明。
<conxtext:annotation-config />
:
这告诉Spring容器,从哪里开始搜索那些带注释的bean。这里spring将搜索基础包的所有子包。
您可以在spring上下文模式文件中找到更多信息。以下是spring-context-4.3.xsd
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。
它也在qazxswpoi描述
配置组件扫描指令以与@Configuration类一起使用。提供与Spring XML元素并行的支持。
需要注意的一点是,如果您使用的是Spring Boot,则可以使用@SpringBootApplication注释隐含@Configuration和@ComponentScan。
我找到了这个很好的<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 />
。
Spring允许你做两件事:
1.自动装配
通常在applicationContext.xml中定义bean,并使用构造函数或setter方法连接其他bean。您可以使用XML或注释来连接bean。如果您使用注释,则需要激活注释,并且必须在applicationContext.xml中添加@Autowire
。这将简化applicationContext.xml中标记的结构,因为您不必手动连接bean(构造函数或setter)。您可以使用<bean>
注释,bean将按类型连接。
转义手动XML配置的一步是
2.自动发现
自动发现将XML进一步简化,因为您甚至不需要在applicationContext.xml中添加<context:component-scan>
标记。您只需使用以下注释之一标记特定bean,Spring将自动将标记的bean及其依赖项连接到Spring容器中。注释如下:@ Controller,@ Service,@ Component,@ Repository。通过使用<context:annotation-config />
并指向基础包,Spring将自动发现并将组件连接到Spring容器中。
作为结论:
<context:component-scan />
是为了能够使用@Autowired注释<context:annotation-config>
用于确定特定bean的搜索和自动装配的尝试。<context:component-scan>
激活bean中的许多不同注释,无论它们是以XML还是通过组件扫描定义的。
3.9. Annotation-based container configuration用于在不使用XML的情况下定义bean
有关详细信息,请阅读:
<context:annotation-config />
两者之间的区别非常简单!
<context:component-scan base-package="org.package"/>
使您能够使用仅限于连接属性和bean构造函数的注释!
在哪里
<context:annotation-config />
启用@Component
可以做的所有事情,添加使用刻板印象,例如.. @Service
,@Repository
,<context:annotation-config>
。所以你可以连接整个bean而不仅限于构造函数或属性!
<context:component-scan>
:在spring config xml中扫描并激活已注册bean的注释。
<context:annotation-config>
:Bean注册+ <context:annotation-config />
@Autowired和@Required是目标属性级别,因此bean应该在使用这些注释之前在spring IOC中注册。要启用这些注释,必须注册相应的bean或包含<context:annotation-config />
。即RequiredAnnotationBeanPostProcessor
仅与注册豆类合作。
@Required启用AutowiredAnnotationBeanPostProcessor
处理工具
@Autowired启用@Repository, @Service and @Controller are @Component处理工具
注意:注释本身无关,我们需要一个Processing Tool,它是一个下面的类,负责核心进程。
<context:component-scan>
,他们的目标是班级。
<context:annotation-config />
它扫描包并找到并注册豆子,它包括Migrating XML to Annotations完成的工作。
<context:annotation-config>
<context:annotation-config>
标记告诉Spring扫描代码库以自动解析包含@Autowired注释的类的依赖性要求。
Spring 2.5还增加了对JSR-250注释的支持,例如@ Resource,@ PostConstruct和@PreDestroy。使用这些注释也需要在Spring容器中注册某些BeanPostProcessors。与往常一样,这些可以注册为单独的bean定义,但也可以通过在spring配置中包含Annotation Based Configuration标记来隐式注册它们。
取自org.springframework.stereotype的Spring文档
Spring提供了自动检测“原型”类并使用ApplicationContext注册相应BeanDefinition的功能。
根据<context:component-scan>
的javadoc:
构造型是注释,表示类型或方法在整体架构中的作用(在概念而非实现级别)。示例:@Controller @Service @Repository等。这些用于工具和方面(为切入点制作理想的目标)。
要自动检测这种“刻板印象”类,需要使用<context:component-scan>
标签。
<context:annotation-config>
标记还告诉Spring在指定的包(及其所有子包)下扫描可注入bean的代码。
<context:annotation-config>
只解析@Autowired和@Qualifer注释,这就是所有,它关于依赖注入,还有其他注释做同样的工作,我想@Inject如何,但所有关于通过注释解决DI。
请注意,即使您已经声明了<bean>
元素,您也必须将您的类声明为Bean,请记住我们有三个可用选项
<context:component-scan>
现在用
<context:annotation-config>
它做了两件事:
<context:component-scan>
相同。因此,如果您声明<context:annotation-config>
,则不再需要声明<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" />
。
就这样
例如,常见的情况是通过XML声明bean,并通过注释解析DI
<constructor-arg>
我们只宣布了bean,没有关于<property>
和<context:component-scan /> implicitly enables <context:annotation-config/>
,DI是通过@Autowired在他们自己的类中配置的。这意味着服务使用@Autowired作为其存储库组件,而存储库使用@Autowired作为JdbcTemplate,DataSource等组件。
<context:component-scan base-package="..." annotation-config="false"/>
尝试使用<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. -->
,在你的配置@ Service,@ Repository,@ Component可以正常工作,但@ Autowired,@ Resource和@Inject不起作用。
这意味着不会启用AutowiredAnnotationBeanPostProcessor,并且Spring容器不会处理自动装配注释。