当前位置:首页 > 前端设计 > 正文

assert的用法 c语言中assert的用法

assert的用法 c语言中assert的用法

各位老铁们好,相信很多人对assert的用法都不是特别的了解,因此呢,今天就来为大家分享下关于assert的用法以及c语言中assert的用法的问题知识,还望可以帮助大...

各位老铁们好,相信很多人对assert的用法都不是特别的了解,因此呢,今天就来为大家分享下关于assert的用法以及c语言中assert的用法的问题知识,还望可以帮助大家,解决大家的一些困惑,下面一起来看看吧!

Spring如何解决循环依赖的问题

1.由同事抛的一个问题开始

最近项目组的一个同事遇到了一个问题,问我的意见,一下子引起的我的兴趣,因为这个问题我也是第一次遇到。平时自认为对spring循环依赖问题还是比较了解的,直到遇到这个和后面的几个问题后,重新刷新了我的认识。

我们先看看当时出问题的代码片段:

@ServicepublicclassTestService1{@AutowiredprivateTestService2testService2;@Asyncpublicvoidtest1(){}}

@ServicepublicclassTestService2{@AutowiredprivateTestService1testService1;publicvoidtest2(){}}

这两段代码中定义了两个Service类:TestService1和TestService2,在TestService1中注入了TestService2的实例,同时在TestService2中注入了TestService1的实例,这里构成了循环依赖。

只不过,这不是普通的循环依赖,因为TestService1的test1方法上加了一个@Async注解。

大家猜猜程序启动后运行结果会怎样?

org.springframework.beans.factory.BeanCurrentlyInCreationException:Errorcreatingbeanwithname'testService1':Beanwithname'testService1'hasbeeninjectedintootherbeans[testService2]initsrawversionaspartofacircularreference,buthaseventuallybeenwrapped.Thismeansthatsaidotherbeansdonotusethefinalversionofthebean.Thisisoftentheresultofover-eagertypematching-considerusing'getBeanNamesOfType'withthe'allowEagerInit'flagturnedoff,forexample.

报错了。。。原因是出现了循环依赖。

「不科学呀,spring不是号称能解决循环依赖问题吗,怎么还会出现?」

如果把上面的代码稍微调整一下:

@ServicepublicclassTestService1{@AutowiredprivateTestService2testService2;publicvoidtest1(){}}

把TestService1的test1方法上的@Async注解去掉,TestService1和TestService2都需要注入对方的实例,同样构成了循环依赖。

但是重新启动项目,发现它能够正常运行。这又是为什么?

带着这两个问题,让我们一起开始spring循环依赖的探秘之旅。

2.什么是循环依赖?

循环依赖:说白是一个或多个对象实例之间存在直接或间接的依赖关系,这种依赖关系构成了构成一个环形调用。

第一种情况:自己依赖自己的直接依赖

第二种情况:两个对象之间的直接依赖

第三种情况:多个对象之间的间接依赖

前面两种情况的直接循环依赖比较直观,非常好识别,但是第三种间接循环依赖的情况有时候因为业务代码调用层级很深,不容易识别出来。

3.循环依赖的N种场景

spring中出现循环依赖主要有以下场景:

单例的setter注入

这种注入方式应该是spring用的最多的,代码如下:

@ServicepublicclassTestService1{@AutowiredprivateTestService2testService2;publicvoidtest1(){}}

@ServicepublicclassTestService2{@AutowiredprivateTestService1testService1;publicvoidtest2(){}}

这是一个经典的循环依赖,但是它能正常运行,得益于spring的内部机制,让我们根本无法感知它有问题,因为spring默默帮我们解决了。

spring内部有三级缓存:

singletonObjects一级缓存,用于保存实例化、注入、初始化完成的bean实例earlySingletonObjects二级缓存,用于保存实例化完成的bean实例singletonFactories三级缓存,用于保存bean创建工厂,以便于后面扩展有机会创建代理对象。

下面用一张图告诉你,spring是如何解决循环依赖的:

图1

细心的朋友可能会发现在这种场景中第二级缓存作用不大。

那么问题来了,为什么要用第二级缓存呢?

试想一下,如果出现以下这种情况,我们要如何处理?

@ServicepublicclassTestService1{@AutowiredprivateTestService2testService2;@AutowiredprivateTestService3testService3;publicvoidtest1(){}}

@ServicepublicclassTestService2{@AutowiredprivateTestService1testService1;publicvoidtest2(){}}

@ServicepublicclassTestService3{@AutowiredprivateTestService1testService1;publicvoidtest3(){}}

TestService1依赖于TestService2和TestService3,而TestService2依赖于TestService1,同时TestService3也依赖于TestService1。

按照上图的流程可以把TestService1注入到TestService2,并且TestService1的实例是从第三级缓存中获取的。

假设不用第二级缓存,TestService1注入到TestService3的流程如图:

图2

TestService1注入到TestService3又需要从第三级缓存中获取实例,而第三级缓存里保存的并非真正的实例对象,而是ObjectFactory对象。说白了,两次从三级缓存中获取都是ObjectFactory对象,而通过它创建的实例对象每次可能都不一样的。

这样不是有问题?

为了解决这个问题,spring引入的第二级缓存。上面图1其实TestService1对象的实例已经被添加到第二级缓存中了,而在TestService1注入到TestService3时,只用从第二级缓存中获取该对象即可。

图3

还有个问题,第三级缓存中为什么要添加ObjectFactory对象,直接保存实例对象不行吗?

答:不行,因为假如你想对添加到三级缓存中的实例对象进行增强,直接用实例对象是行不通的。

针对这种场景spring是怎么做的呢?

答案就在AbstractAutowireCapableBeanFactory类doCreateBean方法的这段代码中:

它定义了一个匿名内部类,通过getEarlyBeanReference方法获取代理对象,其实底层是通过AbstractAutoProxyCreator类的getEarlyBeanReference生成代理对象。

多例的setter注入

这种注入方法偶然会有,特别是在多线程的场景下,具体代码如下:

@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)@ServicepublicclassTestService1{@AutowiredprivateTestService2testService2;publicvoidtest1(){}}

@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)@ServicepublicclassTestService2{@AutowiredprivateTestService1testService1;publicvoidtest2(){}}

很多人说这种情况spring容器启动会报错,其实是不对的,我非常负责任的告诉你程序能够正常启动。

为什么呢?

其实在AbstractApplicationContext类的refresh方法中告诉了我们答案,它会调用finishBeanFactoryInitialization方法,该方法的作用是为了spring容器启动的时候提前初始化一些bean。该方法的内部又调用了preInstantiateSingletons方法

标红的地方明显能够看出:非抽象、单例并且非懒加载的类才能被提前初始bean。

而多例即SCOPE_PROTOTYPE类型的类,非单例,不会被提前初始化bean,所以程序能够正常启动。

如何让他提前初始化bean呢?

只需要再定义一个单例的类,在它里面注入TestService1

@ServicepublicclassTestService3{@AutowiredprivateTestService1testService1;}

重新启动程序,执行结果:

Requestedbeaniscurrentlyincreation:Isthereanunresolvablecircularreference?

果然出现了循环依赖。

注意:这种循环依赖问题是无法解决的,因为它没有用缓存,每次都会生成一个新对象。

构造器注入

这种注入方式现在其实用的已经非常少了,但是我们还是有必要了解一下,看看如下代码:

@ServicepublicclassTestService1{publicTestService1(TestService2testService2){}}

@ServicepublicclassTestService2{publicTestService2(TestService1testService1){}}

运行结果:

Requestedbeaniscurrentlyincreation:Isthereanunresolvablecircularreference?

出现了循环依赖,为什么呢?

从图中的流程看出构造器注入没能添加到三级缓存,也没有使用缓存,所以也无法解决循环依赖问题。

单例的代理对象setter注入

这种注入方式其实也比较常用,比如平时使用:@Async注解的场景,会通过AOP自动生成代理对象。

我那位同事的问题也是这种情况。

@ServicepublicclassTestService1{@AutowiredprivateTestService2testService2;@Asyncpublicvoidtest1(){}}

@ServicepublicclassTestService2{@AutowiredprivateTestService1testService1;publicvoidtest2(){}}

从前面得知程序启动会报错,出现了循环依赖:

org.springframework.beans.factory.BeanCurrentlyInCreationException:Errorcreatingbeanwithname'testService1':Beanwithname'testService1'hasbeeninjectedintootherbeans[testService2]initsrawversionaspartofacircularreference,buthaseventuallybeenwrapped.Thismeansthatsaidotherbeansdonotusethefinalversionofthebean.Thisisoftentheresultofover-eagertypematching-considerusing'getBeanNamesOfType'withthe'allowEagerInit'flagturnedoff,forexample.

为什么会循环依赖呢?

答案就在下面这张图中:

说白了,bean初始化完成之后,后面还有一步去检查:第二级缓存和原始对象是否相等。由于它对前面流程来说无关紧要,所以前面的流程图中省略了,但是在这里是关键点,我们重点说说:

那位同事的问题正好是走到这段代码,发现第二级缓存和原始对象不相等,所以抛出了循环依赖的异常。

如果这时候把TestService1改个名字,改成:TestService6,其他的都不变。

@ServicepublicclassTestService6{@AutowiredprivateTestService2testService2;@Asyncpublicvoidtest1(){}}

再重新启动一下程序,神奇般的好了。

what?这又是为什么?

这就要从spring的bean加载顺序说起了,默认情况下,spring是按照文件完整路径递归查找的,按路径+文件名排序,排在前面的先加载。所以TestService1比TestService2先加载,而改了文件名称之后,TestService2比TestService6先加载。

为什么TestService2比TestService6先加载就没问题呢?

答案在下面这张图中:

这种情况testService6中其实第二级缓存是空的,不需要跟原始对象判断,所以不会抛出循环依赖。

DependsOn循环依赖

还有一种有些特殊的场景,比如我们需要在实例化BeanA之前,先实例化BeanB,这个时候就可以使用@DependsOn注解。

@DependsOn(value="testService2")@ServicepublicclassTestService1{@AutowiredprivateTestService2testService2;publicvoidtest1(){}}

@DependsOn(value="testService1")@ServicepublicclassTestService2{@AutowiredprivateTestService1testService1;publicvoidtest2(){}}

程序启动之后,执行结果:

Circulardepends-onrelationshipbetween'testService2'and'testService1'

这个例子中本来如果TestService1和TestService2都没有加@DependsOn注解是没问题的,反而加了这个注解会出现循环依赖问题。

这又是为什么?

答案在AbstractBeanFactory类的doGetBean方法的这段代码中:

它会检查dependsOn的实例有没有循环依赖,如果有循环依赖则抛异常。

4.出现循环依赖如何解决?

项目中如果出现循环依赖问题,说明是spring默认无法解决的循环依赖,要看项目的打印日志,属于哪种循环依赖。目前包含下面几种情况:

生成代理对象产生的循环依赖

这类循环依赖问题解决方法很多,主要有:

使用@Lazy注解,延迟加载使用@DependsOn注解,指定加载先后关系修改文件名称,改变循环依赖类的加载顺序

使用@DependsOn产生的循环依赖

这类循环依赖问题要找到@DependsOn注解循环依赖的地方,迫使它不循环依赖就可以解决问题。

多例循环依赖

这类循环依赖问题可以通过把bean改成单例的解决。

构造器循环依赖

这类循环依赖问题可以通过使用@Lazy注解解决。

最后说一句(求关注,别白嫖我)

如果这篇文章对您有所帮助,或者有所启发的话,帮忙扫描下发二维码关注一下,您的支持是我坚持写作最大的动力。

求一键三连:点赞、转发、在看。

在公众号中回复:面试、代码神器、开发手册、时间管理有超赞的粉丝福利,另外回复:加群,可以跟很多BAT大厂的前辈交流和学习。

阿布p4调试方法

阿布P4调试的方法首先是需要对P4语言以及网络协议有一定的基础了解。其次需要使用P4调试工具集,如P4BehavioralModel(BMv2),Wireshark等,通过排查、跟踪、捕获数据包等方法,来确定P4程序的正确性和网络协议的实现是否符合预期。

在调试过程中,可以适当地加入assert语句来检查程序的正确性,也可以通过加入一些打印语句来输出重要的中间结果,以方便程序调试和排查问题。总之,阿布P4调试需要具备扎实的理论知识和丰富的实践经验,需要不断学习发现和解决问题的能力。

C++中的断言的用法。ASSERT

assert是包含在头文件<cassert>中的宏定义,如下:

#ifdefNDEBUG#defineassert(condition)((void)0)#else#defineassert(condition)/*implementationdefined*/#endif

由此可见,当NDEBUG已经定义时,assert没有任何作用。反之,condition为零时,assert会终止程序。

通常,debug(调试)模式下不会定义NDEBUG;而release(发布)模式下,会定义NDEBUG。由此可知,assert是用于调试的命令。

一般而言,在编写程序时,我们会假设输入、输出满足一定的条件。由于程序员的疏忽,我们不太可能一次就写对程序。当出现错误时,我们所做的假设可能会不成立。如果我们能将所有假设都用assert进行判断,那么程序出错时,我们能在第一时间发现问题所在。另一方面,我们希望对假设条件的判断不会影响程序的效率。因此,当我们确信程序没有错误时,我们希望assert什么都不做。请看如下示例:

#include<cassert>template<typenameT>Tmultiply(Tconst&a,Tconst&b){returna*b;}template<typenameT>Tdiv(Tconst&a,Tconst&b){returna/b;}intmain(){doubleconsta=1,b=2;assert(multiply(div(a,b),b)==a);return0;}

其中定义了multiple(乘法),div(除法)操作。表面上,我们并没有什么错误,不过为了保险起见,我们使用了assert进行验证。结果正如我们希望的,没有任何错误。然而,当我们将a,b的类型改为int时,程序出错了(debug模式)。因为,div的定义其实是有问题的(相信楼主能看出来吧^^)。

总之,每当我们对程序有任何假设、期望,都应该将它转化为assert语句写入程序当中。它能帮助我们定位错误的位置,缩短调试时间,百利而无一害。

PS:需要注意的是assert应该用于处理程序中的逻辑错误,而不是输入错误。因此判断文件打开是否出错,应该使用异常等错误处理机制,而不是assert。

python中equal的使用

Python中的assertEqual()是单元测试库函数,用于单元测试中以检查两个值的相等性。此函数将使用三个参数作为输入,并根据断言条件返回布尔值。如果两个输入值相等,则assertEqual()将返回true,否则返回false。

用法:assertEqual(firstValue,secondValue,message)

参数:assertEqual()接受以下说明的三个参数:

firstValue按功能比较中使用的任何类型的变量

secondValue:按功能比较时使用的任何类型的变量

message:作为测试消息失败时显示的消息的字符串语句。

python中for属于合法变量吗

python中for不属于合法变量

事实上在python执行如下代码会报错

for=123

这是因为for是Python里面的关键字,是保留字符,关键字是指被编程语言内部定义并保留使用的标识符。

python保留字:and、as、assert、break、class、continue、def、del、elif、if、else、exec、for、finally、from、globa、import、in、is、print、try等等。这些字符都不能用作变量!

rust怎么输代码

在IDEA中安装Rust插件后,可以使用简写,加速输入,就会生成一些模板化代码,如果熟练掌握就可以加快输入。

如输入println!("");,只需要输一个p等一下回车,就可以输入带出整个println!("");

aassert!($END$);aeassert_eq!($LEFT$,$RIGHT$);bfn#[bench]fn$NAME$(b:&muttest::Bencher){b.iter(||);$END$}closure|$PARAM$|$PA

如果你还想了解更多这方面的信息,记得收藏关注本站。

最新文章