首页>>后端>>Spring->Spring的成长之注解@Configuration和@Component

Spring的成长之注解@Configuration和@Component

时间:2023-11-29 本站 点击:0

有迷茫,就会有困惑,有困惑,就有寻找答案的动力,尽管这一过程并不舒服,但是正如士兵突击里面许三多说的,人不能过的太舒服

前言

我一直有一个疑问,就是@Configuration 和 @Component有什么区别?他们都能将对象放入spring容器,那他们的区别是什么呢?

带着这个困惑,今天终于找到了答案。

@Configuration 注解:

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Componentpublic@interfaceConfiguration{Stringvalue()default"";}

上一篇中,我有说过@Configuration是 @Component的派生注解,@Configuration包含@Component的所有功能,那他本身有什么特性呢?他是怎么实现将类放入Spring容器的呢,我们来看看

特性:

配置类必须以类的形式提供(不能是工厂方法返回的实例),允许通过生成子类在运行时增强(cglib 动态代理)。

配置类不能是 final 类(没法动态代理)。

配置注解通常为了通过 @Bean 注解生成 Spring 容器管理的类,

配置类必须是非本地的(即不能在方法中声明,不能是 private)。

任何嵌套配置类都必须声明为static。

@Bean 方法可能不会反过来创建进一步的配置类(也就是返回的 bean 如果带有 @Configuration,也不会被特殊处理,只会作为普通的 bean)。

从特性中我们发现,@Configuration将配置的类放入容器实际是通过动态代理来实现的,通过具体的代码查看在ConfigurationClassPostProcessor中的postProcessBeanFactory方法中调用了下面的方法:

/***Post-processesaBeanFactoryinsearchofConfigurationclassBeanDefinitions;*anycandidatesarethenenhancedbya{@linkConfigurationClassEnhancer}.*CandidatestatusisdeterminedbyBeanDefinitionattributemetadata.*@seeConfigurationClassEnhancer*/publicvoidenhanceConfigurationClasses(ConfigurableListableBeanFactorybeanFactory){Map<String,AbstractBeanDefinition>configBeanDefs=newLinkedHashMap<String,AbstractBeanDefinition>();for(StringbeanName:beanFactory.getBeanDefinitionNames()){BeanDefinitionbeanDef=beanFactory.getBeanDefinition(beanName);//查询系统中所有带有@Configuration的bean定义if(ConfigurationClassUtils.isFullConfigurationClass(beanDef)){//省略部分代码//将@Configuration的bean定义放入MAP集合configBeanDefs.put(beanName,(AbstractBeanDefinition)beanDef);}}if(configBeanDefs.isEmpty()){//nothingtoenhance->returnimmediatelyreturn;}ConfigurationClassEnhancerenhancer=newConfigurationClassEnhancer();for(Map.Entry<String,AbstractBeanDefinition>entry:configBeanDefs.entrySet()){AbstractBeanDefinitionbeanDef=entry.getValue();//Ifa@Configurationclassgetsproxied,alwaysproxythetargetclassbeanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE,Boolean.TRUE);try{//Setenhancedsubclassoftheuser-specifiedbeanclassClass<?>configClass=beanDef.resolveBeanClass(this.beanClassLoader);//使用动态代理增强后的类替换原有的类cglib动态代理的方式,见下面代码:Class<?>enhancedClass=enhancer.enhance(configClass,this.beanClassLoader);if(configClass!=enhancedClass){//省略部分代码beanDef.setBeanClass(enhancedClass);}}catch(Throwableex){thrownewIllegalStateException("Cannotloadconfigurationclass:"+beanDef.getBeanClassName(),ex);}}}

cglib动态里生成增强类:

privateEnhancernewEnhancer(Class<?>superclass,ClassLoaderclassLoader){Enhancerenhancer=newEnhancer();//cglib的动态代理是通过生成子类的形式enhancer.setSuperclass(superclass);enhancer.setInterfaces(newClass[]{ConfigurationClassEnhancer.EnhancedConfiguration.class});enhancer.setUseFactory(false);enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);enhancer.setStrategy(newConfigurationClassEnhancer.BeanFactoryAwareGeneratorStrategy(classLoader));enhancer.setCallbackFilter(CALLBACK_FILTER);enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());returnenhancer;}

通过 cglib 代理的类在调用方法时,会通过CallbackFilter调用:

privatestaticfinalCallback[]CALLBACKS=newCallback[]{newBeanMethodInterceptor(),newBeanFactoryAwareMethodInterceptor(),NoOp.INSTANCE};privatestaticfinalConditionalCallbackFilterCALLBACK_FILTER=newConditionalCallbackFilter(CALLBACKS);

最终会匹配BeanMethodInterceptor 与BeanFactoryAwareMethodInterceptor类的 isMatch方法:

publicbooleanisMatch(MethodcandidateMethod){returnBeanAnnotationHelper.isBeanAnnotated(candidateMethod);}
publicbooleanisMatch(MethodcandidateMethod){returncandidateMethod.getName().equals("setBeanFactory")&&candidateMethod.getParameterTypes().length==1&&BeanFactory.class==candidateMethod.getParameterTypes()[0]&&BeanFactoryAware.class.isAssignableFrom(candidateMethod.getDeclaringClass());}

最终将@Bean修饰的对象放入Spring容器。

这里我们就十分清晰了@Configuration 的实现原理。

而@Component并没有使用动态代理,他是会直接将配置类放入spring容器。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:/Spring/284.html