@Component和@Configuration作为配置类的差别

随着spingboot的大火,注解式配置受到了大家的热烈欢迎,而@Component和@Configuration都可以作为配置类,之前一直都没觉得这两个用起来有什么差别,可能有时程序跑的和自己想的有所区别也没注意到。

直到看到这篇文章:https://my.oschina.net/guangshan/blog/1807721 。我意识到@Component和@Configuration是有区别的,错误的使用可能会导致严重的后果。

请看下面一段代码:

@Configuration
public class MyTestConfig {@Beanpublic Driver driver(){Driver driver = new Driver();driver.setId(1);driver.setName("driver");driver.setCar(car());return driver;}@Beanpublic Car car(){Car car = new Car();car.setId(1);car.setName("car");return car;}
}测试代码如下@RunWith(SpringRunner.class)
@SpringBootTest
public class TestApplicationTests {@Autowiredprivate Car car;@Autowiredprivate Driver driver;@Testpublic void contextLoads() {boolean result = driver.getCar() == car;System.out.println(result ? "同一个car" : "不同的car");}}打印结果如下:
同一个car

替换为Component后的打印结果:

不同的car

从上面的结果可以发现使用Configuration时在driver和spring容器之中的是同一个对象,而使用Component时是不同的对象。
造成不同结果的原因在ConfigurationClassPostProcessor类之中,通过调用enhanceConfigurationClasses方法,为被注解@Configuration的类进行CGLIB代理,代码如下:

public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<String, AbstractBeanDefinition>();for (String beanName : beanFactory.getBeanDefinitionNames()) {BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {//判断是否被@Configuration标注if (!(beanDef instanceof AbstractBeanDefinition)) {throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +beanName + "' since it is not stored in an AbstractBeanDefinition subclass");}else if (logger.isWarnEnabled() && beanFactory.containsSingleton(beanName)) {logger.warn("Cannot enhance @Configuration bean definition '" + beanName +"' since its singleton instance has been created too early. The typical cause " +"is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +"return type: Consider declaring such methods as 'static'.");}configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);}}if (configBeanDefs.isEmpty()) {// nothing to enhance -> return immediatelyreturn;}ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {AbstractBeanDefinition beanDef = entry.getValue();// If a @Configuration class gets proxied, always proxy the target classbeanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);try {// Set enhanced subclass of the user-specified bean classClass<?> configClass = beanDef.resolveBeanClass(this.beanClassLoader);Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);//生成代理的classif (configClass != enhancedClass) {if (logger.isDebugEnabled()) {logger.debug(String.format("Replacing bean definition '%s' existing class '%s' with " +"enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));}//替换class,将原来的替换为CGLIB代理的classbeanDef.setBeanClass(enhancedClass);}}catch (Throwable ex) {throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), ex);}}}

判断是否为配置类的代码如下:

//是否为配置类
public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
return (isFullConfigurationCandidate(metadata) || isLiteConfigurationCandidate(metadata));
}//是否为完整配置类
public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {
return metadata.isAnnotated(Configuration.class.getName());
}
//是否为精简配置类
public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) {// Do not consider an interface or an annotation...if (metadata.isInterface()) {return false;}// Any of the typical annotations found?for (String indicator : candidateIndicators) {if (metadata.isAnnotated(indicator)) {return true;}}// Finally, let's look for @Bean methods...try {return metadata.hasAnnotatedMethods(Bean.class.getName());}catch (Throwable ex) {if (logger.isDebugEnabled()) {logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);}return false;}
}
//精简配置类包含的注解
static {candidateIndicators.add(Component.class.getName());candidateIndicators.add(ComponentScan.class.getName());candidateIndicators.add(Import.class.getName());candidateIndicators.add(ImportResource.class.getName());
}

从上面可以看到,虽然Component注解也会当做配置类,但是并不会为其生成CGLIB代理Class,所以在生成Driver对象时和生成Car对象时调用car()方法执行了两次new操作,所以是不同的对象。当时Configuration注解时,生成当前对象的子类Class,并对方法拦截,第二次调用car()方法时直接从BeanFactory之中获取对象,所以得到的是同一个对象。

至于产生CGLIB代理的流程,可以看一下下面链接,其中含有详细介绍:https://my.oschina.net/guangshan/blog/1807721

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vs 中使用32 位mysql_vs2010连接mysql数据库(含win32和x64两种平台)

数据库安装&#xff1a; 此处有两种安装方式&#xff0c;第一种使用xxx.msi图形化安装方式&#xff0c;和普通的exe软件安装方式一样&#xff0c;按照默认选项一直下一步就可以。mysql下载地址为http://dev.mysql.com/downloads/windows/installer/ 第二种是在mysql官网下载zip…

电脑时间校对器_笔记本电脑如何保养?华为教你五招轻松延长使用时间

集微网7月11日消息(文/数码控)&#xff0c;近日华为花粉俱乐部官方微信公众号发表长文教用户如何保养笔记本电脑&#xff0c;具体有以下五招&#xff1a;

Spring @Configuration 和 @Component 区别

Spring Configuration 和 Component 区别 一句话概括就是 Configuration 中所有带 Bean 注解的方法都会被动态代理&#xff0c;因此调用该方法返回的都是同一个实例。 下面看看实现的细节。 Configuration 注解&#xff1a; Target(ElementType.TYPE) Retention(RetentionPol…

django mysql 过滤所有id_Django数据库中常用的过滤操作

# 获取所有数据&#xff0c;返回QuerySet&#xff0c;里面包含的是对象models.DjangoInfo.objects.all()# 获取所有的id&#xff0c;name数据&#xff0c;返回QuerySet&#xff0c;里面包含的是字典models.DjangoInfo.objects.all().values("id","name")# …

uvc能支持多大分辨率_华为手环B5测评:该有的功能一个不缺,甚至还能变身蓝牙耳机...

前阵子&#xff0c;华为召开nova5系列新品发布会的同时&#xff0c;也给用户们带来了华为手环B5的新配色--铅石青。华为手环B5在去年7月发布&#xff0c;分为三个版本&#xff1a;运动版999元、商务版1199元、时尚版1499元。​此次更新的是运动版&#xff0c;售价仍为999元&…

springboot整合Mybatis提示org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)

在用maven配置mybatis环境时出现此BindingExceptiony异常&#xff0c;发现在classes文件下没有mapper配置文件&#xff0c;应该是maven项目没有扫描到mapper包下的xml文件&#xff0c; 在pom.xml中加入一下代码可以解决&#xff1a; 1.首先在pom.xml中,将xxxmapper.xml添加到类…

cf不能全屏win7的解决方法_win7系统局域网不能访问怎么办 win7局域网不能访问解决方法...

在局域网当中比较实用的功能要数共享文件了&#xff0c;局域网共享可以让用户们共享和管理资源更加便捷&#xff0c;可以大大提高工作效率&#xff0c;不过最近有位win7系统用户使用电脑的时候&#xff0c;发现电脑无法访问局域网中的其他任何一台电脑&#xff0c;这让用户不知…

CGLib动态代理原理

CGLib动态代理原理 CGLib动态代理是代理类去继承目标类&#xff0c;然后重写其中目标类的方法啊&#xff0c;这样也可以保证代理类拥有目标类的同名方法&#xff1b; 看一下CGLib的基本结构&#xff0c;下图所示&#xff0c;代理类去继承目标类&#xff0c;每次调用代理类的方…

sql读取excel数据_Python 读取 Excel 数据,并插入到MySQL

说实话&#xff0c;个人不建议用Python来读取Excel进行入库操作&#xff0c;有条件的话&#xff0c;可以尝试用 ETL 工具&#xff0c;快速导入到MySQL中&#xff0c;或者也可使用 SQL 的导入工具进行。写本文的目的在于&#xff1a;记录一下之前做过一次这个同类型的东西。也为…

无向图的深度优先遍历非递归_图算法总结

&#xfeff;[TOC]图算法1、图的表示1.1、邻接矩阵&#xff08;有向图、无向图、带权图、代码实现&#xff09;1、无向图的邻接矩阵 2、有向图的邻接矩阵 3、带权值的图 有了上述的理解&#xff0c;我们可以设计数据结构&#xff0c;并实现了。C实现如下&#xff1a;#include1.…

华为ipd项目管理流程_IPD:一套卓越的产品开发经营体系

IPD全流程指的不仅仅是“产品开发流程”&#xff0c;而是如何实现产品“从机会到商业变现”的全流程。华为通过20年的全流程实践&#xff0c;才做到持续性推出高质量产品和解决方案。本期IPD全流程班&#xff0c;帮助企业研发管理者学习这套结构化流程&#xff0c;其中划下重点…

brew 安装mysql5.6_MacOS 10.14安装和brew更新后无法安装mysql gem

在macOS 10.14安装Brew更新后,我的开发系统坏了.我无法安装mysql gem.在尝试安装时,我得到&#xff1a;$gem install mysql -v 2.8.1 --source http://rubygems.org/Building native extensions. This could take a while...ERROR: Error installing mysql:ERROR: Failed to bu…

Springboot中@ComponentScan 注解

三个点&#xff1a; 1、工程中Application类的位置。默认情况下就不需要配置ComponentScan这个注解了。 因为Application类&#xff0c;在启动的时候&#xff0c;默认是加载和Application类所在同一个目录下的所有类&#xff0c;包括所有子目录下的类。所以一般情况下&#xff…

在react里写原生js_小程序原生开发与第三方框架选择

最近正在更新《微信小程序入门与实践》一书的第二版。书中有一章节谈到了”多样化的小程序开发“&#xff0c;摘取并加以整理分享给各位开发者。我一向不推荐也不提倡公众号阅读学习编程&#xff0c;文章更多的是列出小程序如今多样化的框架选择&#xff0c;并简单剖析它们之间…

springboot中service层注入的是实现类,但Controller层接收的是接口

我们习惯这样编写代码&#xff1a; 在service层写接口&#xff0c;然后用实现类去实现接口&#xff0c;并且将实现类注入到容器中 Service public class AccountServiceImpl implements AccountService {}在controller层却是用接口操作service的bean的方法&#xff0c; Auto…

mysql data transfer_MySQL主从同步加速 Transfer-- FAQ

Q: Transfer是什么A: 是一个解决MySQL原生主从同步延迟的方案。 Transfer本身是一个在MySQL源码上打的patch&#xff0c;可以用于当Slave&#xff0c;也可以用于当第三方工具&#xff0c;将Master的数据同步发给Slave。 利用多线程实现主从无延迟。Q: Transfer目前的发布形式&a…

springboot整合mybatisplus中@Mapper与@MapperScan的使用

一、Mapper与MapperScan不可同时使用 二、Mapper用于注解单个mapper接口 三、Mapper Scan用于批量注解Mapper接口 四、Mapper不起作用时&#xff0c;因为缺少下图中的依赖包 以上为自己整合框架中遇到的问题与解决方案&#xff0c;如果以上解决方案不能解决您的问题&#x…

html列表按时间排序代码_按字母顺序排序的列表

有时候你需要自制一份课件PPT或者手写笔记的关键词索引&#xff0c;用来开卷考试查阅PPT或者复习查阅笔记时能快速定位查阅内容位置&#xff0c;这时你可能想要一个按字母顺序排序的列表来帮助构建需要的索引。LaTeX自身的index本身并不支持这样的功能&#xff0c;修改起来也颇…

@MapperScan和@ComponentScan使用问题

报错如下 原因&#xff1a;当MapperScan和ComponentScan一起使用时&#xff0c;项目启动时扫描包会发生冲突&#xff0c;找不到swagger配置类的包和mapper接口的包 解决办法&#xff1a;MapperScan和ComponentScan可以一起使用。 改为MapperScan&#xff08;basePackages {}…

C语言中CY位什么时候才能为1_你真的了解C语言中的整型吗?

整型数据类型1. 整型数据类型在上一节当中&#xff0c;我们遇到了整型(integer)int&#xff0c;用来表示一个整数的数据类型。下面呢我们来讨论一下C语言里面的整数数据类型。看到这里你可能想问&#xff0c;一个整数而已&#xff0c;为什么会需要定义这么多的类型出来呢?要知…