use*_*097 672 java configuration spring annotations spring-3
我正在学习春天3,我似乎没有把握背后的功能<context:annotation-config>和<context:component-scan>.
根据我的阅读,他们似乎处理不同的注释(@ Required,@ Autowired etc vs @Component,@ Repository,@ Service等),但也从我读过的内容中注册了相同的bean后处理器类.
为了让我更加困惑,有一个@Required属性@Autowired.
有人可以对这些标签有所了解吗?什么是相似的,什么是不同的,一个被另一个取代,它们相互完成,我需要其中一个,两者都有吗?
小智 1392
<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;
}
}
Run Code Online (Sandbox Code Playgroud)
使用以下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>
Run Code Online (Sandbox Code Playgroud)
加载上下文会产生以下输出:
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
Run Code Online (Sandbox Code Playgroud)
好的,这是预期的输出.但这是春天的"老风格".现在我们有注释,所以让我们使用它们来简化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;
}
}
Run Code Online (Sandbox Code Playgroud)
这允许我从XML中删除以下行:
<property name="bbb" ref="bBean" />
<property name="ccc" ref="cBean" />
Run Code Online (Sandbox Code Playgroud)
我的XML现在简化为:
<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A" />
Run Code Online (Sandbox Code Playgroud)
当我加载上下文时,我得到以下输出:
creating bean B: com.xxx.B@5e5a50
creating bean C: com.xxx.C@54a328
creating bean A: com.yyy.A@a3d4cf
Run Code Online (Sandbox Code Playgroud)
好的,这是错的!发生了什么?为什么我的房产没有自动装配?
嗯,注释是一个很好的功能,但他们自己什么都不做.他们只是注释东西.您需要一个处理工具来查找注释并使用它们执行某些操作.
<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" />
Run Code Online (Sandbox Code Playgroud)
当我加载应用程序上下文时,我得到了正确的结果:
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
Run Code Online (Sandbox Code Playgroud)
好的,这很好,但是我从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;
}
}
Run Code Online (Sandbox Code Playgroud)
在XML中我们只保留这个:
<context:annotation-config />
Run Code Online (Sandbox Code Playgroud)
我们加载上下文,结果是......没什么.没有创建bean,也没有自动装配bean.没有!
那是因为,正如我在第一段中所说的那样,<context:annotation-config />唯一适用于在应用程序上下文中注册的bean.因为我删除了三个bean的XML配置,所以没有创建bean并且<context:annotation-config />没有"目标"可以处理.
但这不是一个问题<context:component-scan>,可以扫描一个包以寻找"目标".让我们将XML配置的内容更改为以下条目:
<context:component-scan base-package="com.xxx" />
Run Code Online (Sandbox Code Playgroud)
当我加载上下文时,我得到以下输出:
creating bean B: com.xxx.B@1be0f0a
creating bean C: com.xxx.C@80d1ff
Run Code Online (Sandbox Code Playgroud)
嗯......有些东西不见了.为什么?
如果您在班closelly看,类A有包com.yyy,但我已经在指定<context:component-scan>使用的软件包com.xxx所以这完全错过了我的A班,只有拿起B和C它们的com.xxx软件包.
为了解决这个问题,我还添加了另一个包:
<context:component-scan base-package="com.xxx,com.yyy" />
Run Code Online (Sandbox Code Playgroud)
现在我们得到了预期的结果:
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
Run Code Online (Sandbox Code Playgroud)
就是这样!现在您不再拥有XML定义,您有注释.
作为最后一个例子,保留带注释的类A,B并将C以下内容添加到XML中,加载上下文后我们会得到什么?
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />
Run Code Online (Sandbox Code Playgroud)
我们仍然得到正确的结果:
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
Run Code Online (Sandbox Code Playgroud)
即使A没有通过扫描获得类的bean ,处理工具仍然应用于<context:component-scan>在应用程序上下文中注册的所有bean,即使A是在XML中手动注册的bean .
但是,如果我们有以下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" />
Run Code Online (Sandbox Code Playgroud)
不,没有重复,我们再次得到预期的结果:
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
Run Code Online (Sandbox Code Playgroud)
这是因为两个标签都注册了相同的处理工具(<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" />
Run Code Online (Sandbox Code Playgroud)
仍会产生以下结果:
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
Run Code Online (Sandbox Code Playgroud)
好吧,那就是把它搞砸了.
我希望与@Tomasz Nurkiewicz和@Sean帕特里克·弗洛伊德的响应沿着这条信息,都是你需要了解如何
<context:annotation-config>和<context:component-scan>工作.
Tom*_*icz 163
我找到了这个很好的摘要,其中哪些注释被哪些声明所取代.通过研究它,你会发现它<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功能.
use*_*474 94
Spring允许你做两件事:
1.自动装配
通常在applicationContext.xml中定义bean,并使用构造函数或setter方法连接其他bean.您可以使用XML或注释来连接bean.如果您使用注释,则需要激活注释,并且必须<context:annotation-config />在applicationContext.xml中添加
.这将简化applicationContext.xml中标记的结构,因为您不必手动连接bean(构造函数或setter).您可以使用@Autowire注释,bean将按类型进行连接.
转义手动XML配置的一步是
2.自动
发现自动发现将XML进一步简化,因为您甚至不需要<bean>在applicationContext.xml中添加标记.您只需使用以下注释之一标记特定bean,Spring将自动将标记的bean及其依赖项连接到Spring容器中.注解如下: @Controller,@Service,@Component,@Repository.通过使用<context:component-scan>和指向基础包,Spring将自动发现并将组件连接到Spring容器中.
作为结论:
<context:annotation-config />用于能够使用
@Autowired注释<context:component-scan /> 用于确定特定bean的搜索和自动装配的尝试.Sea*_*oyd 35
<context:annotation-config> 激活bean中的许多不同注释,无论它们是以XML还是通过组件扫描定义的.
<context:component-scan> 用于在不使用XML的情况下定义bean
有关详细信息,请阅读:
Spa*_*les 30
两者之间的区别非常简单!
<context:annotation-config />
Run Code Online (Sandbox Code Playgroud)
使您能够使用仅限于连接属性和bean构造函数的注释!
在哪里
<context:component-scan base-package="org.package"/>
Run Code Online (Sandbox Code Playgroud)
启用一切<context:annotation-config />可以做的,与另外使用定型例如..的@Component,@Service,@Repository.所以你可以连接整个bean而不仅限于构造函数或属性!
Pre*_*raj 29
<context:annotation-config>:在spring config xml中扫描并激活已注册bean的注释.
<context:component-scan>: Bean注册+<context:annotation-config>
@Autowired和@Required是目标属性级别,因此bean应该在使用这些注释之前在spring IOC中注册.要启用这些注释,必须注册相应的bean或include <context:annotation-config />.即<context:annotation-config />仅适用于已注册的bean.
@Required启用 RequiredAnnotationBeanPostProcessor 处理工具
@Autowired启用 AutowiredAnnotationBeanPostProcessor处理工具
注意:注释本身无关,我们需要一个Processing Tool,它是一个下面的类,负责核心进程.
@ Repository,@ Service和@Controller是@Component,它们的目标是类级别.
<context:component-scan>它扫描包并查找并注册bean,它包括完成的工作<context:annotation-config />.
Sac*_*rma 15
该<context:annotation-config>标签告诉Spring扫描代码库自动解析包含@Autowired注解类的依赖性要求.
Spring 2.5还增加了对JSR-250注释的支持,例如@ Resource,@ PostConstruct和@PreDestroy.使用这些注释也需要在Spring容器中注册某些BeanPostProcessors.与往常一样,这些可以注册为单独的bean定义,但也可以通过<context:annotation-config>在spring配置中包含tag 来隐式注册它们.
摘自基于注释的配置的 Spring文档
Spring提供了自动检测"原型"类并使用ApplicationContext注册相应BeanDefinition的功能.
根据org.springframework.stereotype的 javadoc :
构造型是注释,表示类型或方法在整体架构中的作用(在概念而非实现级别).示例:@Controller @Service @Repository等.这些用于工具和方面(为切入点制作理想的目标).
要自动检测此类"刻板印象"类,<context:component-scan>需要使用标记.
该<context:component-scan>标记还告诉Spring扫描指定的包(及其所有子包)下的可注入bean的代码.
Man*_*dan 12
<context:annotation-config>
Run Code Online (Sandbox Code Playgroud)
只解析@Autowired和@Qualifer注释,这就是所有,它关于依赖注入,还有其他注释做同样的工作,我想@Inject如何,但所有关于通过注释解决DI.
请注意,即使您声明了<context:annotation-config>元素,也必须将您的类声明为Bean,请记住我们有三个可用选项
<bean> 现在用
<context:component-scan>
Run Code Online (Sandbox Code Playgroud)
它做了两件事:
<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" />
Run Code Online (Sandbox Code Playgroud)
我们只是声明了豆子,一无所知<constructor-arg>而<property>下,二是通过@Autowired配置在自己的班级.这意味着服务使用@Autowired作为其存储库组件,而存储库使用@Autowired作为JdbcTemplate,DataSource等组件.
<context:component-scan /> implicitly enables <context:annotation-config/>
Run Code Online (Sandbox Code Playgroud)
尝试使用<context:component-scan base-package="..." annotation-config="false"/>,在您的配置@Service,@ Repository,@ Component可以正常工作,但@ Autowired,@ Resource和@Inject不起作用.
这意味着不会启用AutowiredAnnotationBeanPostProcessor,并且Spring容器不会处理自动装配注释.
<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. -->
Run Code Online (Sandbox Code Playgroud)
另一个要注意的重点是context:component-scan隐式调用context:annotation-config以激活bean上的注释.好吧,如果你不想context:component-scan为你隐式激活注释,你可以继续设置context:component-scanto 的annotation-config元素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 -->
Run Code Online (Sandbox Code Playgroud)