




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第Component和Configuration注解区别实例详解目录引言AnnotationBean.javaAnnotationTest.javaSpring-source-5.2.8两个注解声明增强逻辑
引言
第一眼看到这个题目,我相信大家都会脑子里面弹出来一个想法:这不都是Spring的注解么,加了这两个注解的类都会被最终封装成BeanDefinition交给Spring管理,能有什么区别?
首先先给大家看一段示例代码:
AnnotationBean.java
importlombok.Data;
importorg.springframework.beans.factory.annotation.Qualifier;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.stereotype.Component;
@Component
//@Configuration
publicclassAnnotationBean{
@Qualifier("innerBean1")
@Bean()
publicInnerBeaninnerBean1(){
returnnewInnerBean();
@Bean
publicInnerBeanFactoryinnerBeanFactory(){
InnerBeanFactoryfactory=newInnerBeanFactory();
factory.setInnerBean(innerBean1());
returnfactory;
publicstaticclassInnerBean{
@Data
publicstaticclassInnerBeanFactory{
privateInnerBeaninnerBean;
}
AnnotationTest.java
@Test
voidtest7(){
AnnotationConfigApplicationContextapplicationContext=newAnnotationConfigApplicationContext(BASE_PACKAGE);
Objectbean1=applicationContext.getBean("innerBean1");
ObjectfactoryBean=applicationContext.getBean("innerBeanFactory");
inthashCode1=bean1.hashCode();
InnerBeaninnerBeanViaFactory=((InnerBeanFactory)factoryBean).getInnerBean();
inthashCode2=innerBeanViaFactory.hashCode();
Assertions.assertEquals(hashCode1,hashCode2);
}
大家可以先猜猜看,这个test7()的执行结果究竟是成功呢还是失败呢?
答案是失败的。如果将AnnotationBean的注解从@Component换成@Configuration,那test7()就会执行成功。
究竟是为什么呢?通常Spring管理的bean不都是单例的么?
别急,让笔者慢慢道来~~~
Spring-source-5.2.8两个注解声明
以下是摘自Spring-source-5.2.8的两个注解的声明
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public@interfaceComponent{
*Thevaluemayindicateasuggestionforalogicalcomponentname,
*tobeturnedintoaSpringbeanincaseofanautodetectedcomponent.
*@returnthesuggestedcomponentname,ifany(oremptyStringotherwise)
Stringvalue()default"";
----------------------------------这是分割线-----------------------------------
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public@interfaceConfiguration{
*ExplicitlyspecifythenameoftheSpringbeandefinitionassociatedwiththe
*{@code@Configuration}class.Ifleftunspecified(thecommoncase),abean
*namewillbeautomaticallygenerated.
*pThecustomnameappliesonlyifthe{@code@Configuration}classispicked
*upviacomponentscanningorsupplieddirectlytoan
*{@linkAnnotationConfigApplicationContext}.Ifthe{@code@Configuration}class
*isregisteredasatraditionalXMLbeandefinition,thename/idofthebean
*elementwilltakeprecedence.
*@returntheexplicitcomponentname,ifany(oremptyStringotherwise)
*@seeAnnotationBeanNameGenerator
@AliasFor(annotation=Component.class)
Stringvalue()default"";
*Specifywhether{@code@Bean}methodsshouldgetproxiedinordertoenforce
*beanlifecyclebehavior,e.g.toreturnsharedsingletonbeaninstanceseven
*incaseofdirect{@code@Bean}methodcallsinusercode.Thisfeature
*requiresmethodinterception,implementedthrougharuntime-generatedCGLIB
*subclasswhichcomeswithlimitationssuchastheconfigurationclassand
*itsmethodsnotbeingallowedtodeclare{@codefinal}.
*pThedefaultis{@codetrue},allowingfor'inter-beanreferences'viadirect
*methodcallswithintheconfigurationclassaswellasforexternalcallsto
*thisconfiguration's{@code@Bean}methods,e.g.fromanotherconfigurationclass.
*Ifthisisnotneededsinceeachofthisparticularconfiguration's{@code@Bean}
*methodsisself-containedanddesignedasaplainfactorymethodforcontaineruse,
*switchthisflagto{@codefalse}inordertoavoidCGLIBsubclassprocessing.
*pTurningoffbeanmethodinterceptioneffectivelyprocesses{@code@Bean}
*methodsindividuallylikewhendeclaredonnon-{@code@Configuration}classes,
*a.k.a."@BeanLiteMode"(see{@linkBean@Bean'sjavadoc}).Itistherefore
*behaviorallyequivalenttoremovingthe{@code@Configuration}stereotype.
*@since5.2
booleanproxyBeanMethods()defaulttrue;
}
从这两个注解的定义中,可能大家已经看出了一点端倪:@Configuration比@Component多一个成员变量booleanproxyBeanMethods()默认值是true.从这个成员变量的注释中,我们可以看到一句话
Specifywhether{@code@Bean}methodsshouldgetproxiedinordertoenforcebeanlifecyclebehavior,e.g.toreturnsharedsingletonbeaninstancesevenincaseofdirect{@code@Bean}methodcallsinusercode.
其实从这句话,我们就可以初步得到我们想要的答案了:在带有@Configuration注解的类中,一个带有@Bean注解的方法显式调用另一个带有@Bean注解的方法,返回的是共享的单例对象.下面我们从Spring源码实现角度来看看这中间的原理.
从Spring源码实现中可以得出一个规律,Spring作者在实现注解时,通常是先收集解析,再调用。@Configuration是基于@Component实现的,在@Component的解析过程中,我们可以看到下面一段逻辑:
org.springframework.context.annotation.ConfigurationClassUtils#checkConfigurationClassCandidate
MapString,Objectconfig=metadata.getAnnotationAttributes(Configuration.class.getName());
if(config!=null!Boolean.FALSE.equals(config.get("proxyBeanMethods"))){
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE,CONFIGURATION_CLASS_FULL);
elseif(config!=null||isConfigurationCandidate(metadata)){
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE,CONFIGURATION_CLASS_LITE);
}
默认情况下,Spring在将带有@Configuration注解的类封装成BeanDefinition的时候,会设置一个属性CONFIGURATION_CLASS_ATTRIBUTE,属性值为CONFIGURATION_CLASS_FULL,反之,如果只有@Component注解,那该属性值就会是CONFIGURATION_CLASS_LITE(这个属性值很重要).在@Component注解的调用过程当中,有下面一段逻辑:
org.springframework.context.annotation.ConfigurationClassPostProcessor#enhanceConfigurationClasses
for(StringbeanName:beanFactory.getBeanDefinitionNames()){
......
if((configClassAttr!=null||methodMetadata!=null)beanDefinstanceofAbstractBeanDefinition){
......
if(ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)){
if(!(beanDefinstanceofAbstractBeanDefinition)){
thrownewBeanDefinitionStoreException("Cannotenhance@Configurationbeandefinition'"+
beanName+"'sinceitisnotstoredinanAbstractBeanDefinitionsubclass");
elseif(logger.isInfoEnabled()beanFactory.containsSingleton(beanName)){
("Cannotenhance@Configurationbeandefinition'"+beanName+
"'sinceitssingletoninstancehasbeencreatedtooearly.Thetypicalcause"+
"isanon-static@BeanmethodwithaBeanDefinitionRegistryPostProcessor"+
"returntype:Considerdeclaringsuchmethodsas'static'.");
configBeanDefs.put(beanName,(AbstractBeanDefinition)beanDef);
if(configBeanDefs.isEmpty()){
//nothingtoenhance-returnimmediately
return;
ConfigurationClassEnhancerenhancer=newConfigurationClassEnhancer();
......
如果BeanDefinition的ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE属性值为ConfigurationClassUtils.CONFIGURATION_CLASS_FULL,则该BeanDefinition对象会被加入到MapString,AbstractBeanDefinitionconfigBeanDefs容器中。
如果Spring发现该Map是空的,则认为不需要进行代理增强,立即返回;反之,则为该类(本文中,被代理类即为AnnotationBean,以下简称该类)创建代理。
所以如果该类的注解是@Component,调用带有@Bean注解的innerBean1()方法时,this对象为Spring容器中的真实单例对象,例如AnnotationBean@4149.
@Bean
publicInnerBeanFactoryinnerBeanFactory(){
InnerBeanFactoryfactory=newInnerBeanFactory();
factory.setInnerBean(innerBean1());
returnfactory;
}
那在上述方法中每调用一次innerBean1()方法时,势必会返回一个新创建的InnerBean对象。如果该类的注解为@Configuration时,this对象为Spring生成的AnnotationBean的代理对象,例如AnnotationBean$$EnhancerBySpringCGLIB$$90f8540c@4296,
增强逻辑
//Thecallbackstouse.Notethatthesecallbacksmustbestateless.
privatestaticfinalCallback[]CALLBACKS=newCallback[]{
newBeanMethodInterceptor(),
newBeanFactoryAwareMethodInterceptor(),
NoOp.INSTANCE
-----------------------------------这是分割线-------------------------------
*CreatesanewCGLIB{@linkEnhancer}instance.
privateEnhancernewEnhancer(ClassconfigSuperClass,@NullableClassLoaderclassLoader){
Enhancerenhancer=newEnhancer();
enhancer.setSuperclass(configSuperClass);
enhancer.setInterfaces(newClass[]{EnhancedConfiguration.class});
enhancer.setUseFactory(false);
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(newBeanFactoryAwareGeneratorStrategy(classLoader));
enhancer.setCallbackFilter(CALLBACK_FILTER);
enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
returnenhancer;
}
当在上述方法中调用innerBean1()时,ConfigurationClassEnhancer遍历3种回调方法判断当前调用应该使用哪个回调方法时,第一个回调类型匹配成功org.springframework.context.annotation.ConfigurationClassEnhancer.BeanMethodInterceptor#isMatch匹配过程如下所示:
@Override
publicbooleanisMatch(MethodcandidateMethod){
return(candidateMethod.getDeclaringClass()!=Object.class!BeanFactoryAwareMethodInterceptor.
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 经济型酒店的市场趋势预测与前瞻考核试卷
- 天然气发电系统技术与效率提升考核试卷
- 科技会展项目管理与实践考核试卷
- 船舶全球市场分析考核试卷
- 软件工程前沿技术探讨考核试卷
- 糖业产业发展策略研究考核试卷
- 财务规划中的资产配置与风险管理考核试卷
- 跨境信用服务考核试卷
- 自行车租赁市场服务个性化发展考核试卷
- 羽绒制品品牌形象与视觉传达设计考核试卷
- 【MOOC】理解马克思-南京大学 中国大学慕课MOOC答案
- JGT266-2011 泡沫混凝土标准规范
- GB/T 94.1-1987弹性垫圈技术条件弹簧垫圈
- GB/T 32512-2016光伏发电站防雷技术要求
- GB/T 30516-2014高粘高弹道路沥青
- GB/T 29602-2013固体饮料
- GB/T 23268.1-2009运动保护装备要求第1部分:登山动力绳
- GB/T 12469-1990焊接质量保证钢熔化焊接头的要求和缺陷分级
- 临床血液学检验技术-其他白细胞疾病
- DBJ-T 13-195-2022 烧结煤矸石实心砖和多孔砖(砌块) 应用技术标准
- FZ/T 21009-2015短毛条
评论
0/150
提交评论