




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第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. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- GB/T 45763-2025精细陶瓷陶瓷薄板室温弯曲强度试验方法三点弯曲或四点弯曲法
- 2025年江西省赣州市会昌中学宁师中学物理高一下期末监测试题含解析
- 山东省枣庄市滕州市滕州市第一中学2025年物理高一下期末统考模拟试题含解析
- 2025届湖北省襄阳第四中学物理高一下期末综合测试模拟试题含解析
- 2025届上海市静安区风华中学物理高一下期末预测试题含解析
- 宣传上课课件
- 2025届山西省朔州市物理高二第二学期期末学业水平测试试题含解析
- 宠物护理与美容课件
- 宠物X光片检查技术课件
- 2025搬家合同范本大全:家具搬运与包装服务细则
- 医药电商区域销售数据特征研究-洞察阐释
- 2025年新修订《治安管理处罚法》
- 【政治 云南卷】2025年云南省高考招生统一考试真题政治试卷(含答案)
- 中式烹调考试试题及答案
- 管道非开挖修复技术课件
- 2025至2030中国工业大麻行业深度调研与投资咨询报告
- 高中数学必修一学业评价计划
- 2024年吉林省省直事业单位招聘考试真题
- 物资采购培训课件
- 2025年湖南省高考历史真题(答案版)
- GB/T 18204.3-2025公共场所卫生检验方法第3部分:空气微生物指标
评论
0/150
提交评论