有迷茫,就会有困惑,有困惑,就有寻找答案的动力,尽管这一过程并不舒服,但是正如士兵突击里面许三多说的,人不能过的太舒服
。
前言
我一直有一个疑问,就是@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容器。