有迷茫,就会有困惑,有困惑,就有寻找答案的动力,尽管这一过程并不舒服,但是正如士兵突击里面许三多说的,人不能过的太舒服。
前言我一直有一个疑问,就是@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注解配置:@Configuration 和 @Component 区别及原理详解_百度知 ...
综上所述,@Component注解标记的配置类在Spring中被视为轻量级配置类,它适用于方法间的简单调用;而@Configuration注解标记的配置类被视为全面型配置类,它支持更复杂的依赖注入和方法间调用。在理解了这些基本原理之后,我们能够更高效地利用Spring框架进行开发,实现更灵活、更强大的应用。
Spring的成长之注解@Configuration和@Component
Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Componentpublic@interfaceConfiguration{Stringvalue()default"";}上一篇中,我有说过@Configuration是@Component的派生注解,@Configuration包含@Component的所有功能,那他本身有什么特性呢?他是怎么实现将类放入Spring容器的呢,我们来看看 ...
@configuration和@component之间的区别是什么?
configuration和@component之间的区别是:@Component注解的范围最广,所有类都可以注解,但是@Configuration注解一般注解在这样的类上:这个类里面有@Value注解的成员变量和@Bean注解的方法,就是一个配置类。configuration和@component相同点是都是注解在类上的注解。Spring 2.5 中除了提供 @Component 注释外,...
springboot三大核心注解是什么?
SpringBoot中的三大核心注解包括@Configuration、@EnableAutoConfiguration和@ComponentScan。首先,@Configuration是Spring Boot中的关键,它标志着一个类可以被Spring IoC容器作为bean的定义源。配合@Bean注解,你可以创建一个简单的配置类,无需依赖XML文件,便能实现Spring应用的配置功能。接下来,@EnableAutoCo...
@configuration和@component之间的区别
区别:1)@Component注解的范围最广,所有类都可以注解;2)@Configuration注解一般注解在这样的类上:这个类里面有@Value注解的成员变量和@Bean注解的方法,就是一个配置类。
springboot三大核心注解是什么?
springboot三大核心注解是@Configuration,@EnableAutoConfiguration和@ComponentScan。提到@Configuration就要提到他的搭档@Bean,使用这两个注解就可以创建一个简单的spring配置类,可以用来替代相应的xml配置文件。springboot三大核心注解的特点 这个注解类标识这个类可以使用SpringIoC容器作为bean定义的来源,@Bean...
springboot三大核心注解是什
SpringBoot中的三大核心注解分别是@Configuration、@EnableAutoConfiguration和@ComponentScan。其中,@Configuration注解的作用至关重要,它标记了一个类可以由Spring IoC容器作为bean的定义源,配合@Bean注解,可以轻松创建简单的配置类,替代传统的XML配置。@Bean注解就像一个指示符,告诉Spring在带有该注解的方法...
@Bean在@Configuration和在@Component中的区别
Spring 注解@Component,@Service,@Controller,@Repository Spring 2.5 中除了提供 @Component 注释外,还定义了几个拥有特殊语义的注释,它们分别是:@Repository、@Service 和 @Controller。在目前的 Spring 版本中,这 3 个注释和 @Component 是等效的,但是从注释类的命名上,很容易看出这 3 个注释...
@bean注解和@component注解的区别(@bean注解的方法可以写参数吗...
configuration和@component之间的区别1、区别:1)@Component注解的范围最广,所有类都可以注解;2)@Configuration注解一般注解在这样的类上:这个类里面有@Value注解的成员变量和@Bean注解的方法,就是一个配置类。2、在Component中(@Component标注的类,包括@Service,@Repository,@Controller)使用@Bean注解...
spring 中 Component和@Configuration分别是什么意思
component 英 [kəmˈpəʊnənt] 美 [kəmˈpoʊnənt]n. 成分;组分;零件;[数]要素 adj. 成分的;组成的;合成的;构成的 configuration 英 [kənˌfɪgəˈreɪʃn] 美 [kən...