当前位置: 首页 > news >正文

做公司网站的价格白百度一下你就知道

做公司网站的价格,白百度一下你就知道,网站程序定制,seo公司优化排名问题呈现 项目性能优化,需要将本地内存(JVM内存)替换为本地Redis(同一个Pod中的Container),降低JVM内存和GC的压力,同时引入了JetCache简化和统一使用(对JetCache也做了扩展&#x…

问题呈现

项目性能优化,需要将本地内存(JVM内存)替换为本地Redis(同一个Pod中的Container),降低JVM内存和GC的压力,同时引入了JetCache简化和统一使用(对JetCache也做了扩展,支持了本地Redis)。引入JetCache后,项目启动就会报循环依赖的错误,错误入口则是项目中使用@PostConstruct调用JetCache加载预热缓存的地方,错误堆栈如下:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'globalCacheConfig' defined in class path resource [cn/jojo/edu/jetcache/autoconfigure/JetCacheAutoConfiguration.class]: Circular depends-on relationship between 'globalCacheConfig' and 'redissonAutoInit'at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:305) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:227) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1155) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveBean(DefaultListableBeanFactory.java:416) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:349) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:342) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]at cn.jojo.edu.jetcache.anno.field.LazyInitCache.init(LazyInitCache.java:83) ~[jetcache-anno-ss2.6.9-20241025.105436-2.jar:?]at cn.jojo.edu.jetcache.anno.field.LazyInitCache.checkInit(LazyInitCache.java:66) ~[jetcache-anno-ss2.6.9-20241025.105436-2.jar:?]at cn.jojo.edu.jetcache.anno.field.LazyInitCache.put(LazyInitCache.java:159) ~[jetcache-anno-ss2.6.9-20241025.105436-2.jar:?]at cn.jojo.edu.malacca.integration.cache.AbstractLocalRedisCacheService.put2Cache(AbstractLocalRedisCacheService.java:92) ~[classes/:?]at cn.jojo.edu.malacca.integration.cache.AbstractLocalRedisCacheService.forceRefreshCache(AbstractLocalRedisCacheService.java:140) ~[classes/:?]at cn.jojo.edu.malacca.api.server.config.PreheatInit.execute(PreheatInit.java:96) ~[classes/:?]at cn.jojo.edu.malacca.api.server.config.PreheatInit.lambda$init$0(PreheatInit.java:73) ~[classes/:?]at cn.jojo.infra.sdk.context.request.RequestContextHolder.setContext(RequestContextHolder.java:162) ~[microservice-sdk-1.7.29.jar:?]at cn.jojo.edu.malacca.api.server.config.PreheatInit.init(PreheatInit.java:71) ~[classes/:?]at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_65]at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_65]at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_65]at java.lang.reflect.Method.invoke(Method.java:497) ~[?:1.8.0_65]at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:389) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:333) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:157) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]... 18 more

看错误日志问题是出在预热调用LazyInitCache.put方法时,该方法内部首先会获取GlobalCacheConfig对象,让其优先初始化,就是在初始化该对象时报的循环依赖错误:
在这里插入图片描述
存在以下几个奇怪的问题:

  1. 错误提示的是globalCacheConfig和redissonAutoInit产生了循环依赖,但是看GlobalCacheConfig本身并没有依赖其它复杂的对象,只是在初始化时依赖了SpringConfigProvider、JetCacheProperties和AutoConfigureBeans,globalCacheConfig和redissonAutoInit的依赖是如何产生的呢?
    在这里插入图片描述
  2. 为什么在@PostConstruct中预热会报错,但在@EventListener(ApplicationReadyEvent.class)中预热却不会报错?
  3. 为什么配置启用了多个缓存组件才会报错,只启用一个缓存组件却不会?
  4. Spring通过三级缓存解决了非构造函数注入产生的循环依赖,那为什么这个循环依赖没有被解决呢?

分析过程

依赖关系分析

在这里插入图片描述RedissonAutoInit对GobalCacheConfig的依赖比较好发现,从图中可以看到是父类中引用了ConfigProvider,在ConfigProvider中又引用了GlobalCacheConfig,不过从图中也无法找出GobalCacheConfig对RedissonAutoInit的依赖从何而来。
于是查看报循环依赖错误的源码:
在这里插入图片描述
这部分源码位于AbstractBeanFactory.doGetBean方法中,在创建Bean之前会对有设置dependsOn属性的BeanDefinition(以下简称BD)校验是否有循环依赖,但是GlobalCacheConfig类中并没有标记@DependsOn注解,还有哪里可以设置呢?不难想到Spring本身提供的一些扩展点是可以修改BD属性的,比如BeanFactoryPostProcessorBeanDefinitionRegistryPostProcessor,最终找到一个BeanFactoryPostProcessor的实现类BeanDependencyManager

public class BeanDependencyManager implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {String[] autoInitBeanNames = beanFactory.getBeanNamesForType(AbstractCacheAutoInit.class, false, false);if (autoInitBeanNames != null) {BeanDefinition bd = beanFactory.getBeanDefinition(JetCacheAutoConfiguration.GLOBAL_CACHE_CONFIG_NAME);String[] dependsOn = bd.getDependsOn();if (dependsOn == null) {dependsOn = new String[0];}int oldLen = dependsOn.length;dependsOn = Arrays.copyOf(dependsOn, dependsOn.length + autoInitBeanNames.length);System.arraycopy(autoInitBeanNames,0, dependsOn, oldLen, autoInitBeanNames.length);bd.setDependsOn(dependsOn);}}}

在这里将获取到的AbstractCacheAutoInit的子类都设置到了GlobalCacheConfig的dependsOn属性中(题外话这里并不是所有实现了AbstractCacheAutoInit的子类都会设置进去,还要看是否满足条件,Jetache提供了JetCacheCondition,只有配置启用了的缓存组件对应的Init才会初始化并设置到dependsOn中)。
至此,循环依赖就产生了。

循环依赖错误根因分析

有了循环依赖,但为什么Spring的三级缓存没有解决该问题,以及为什么是在某些条件下才会报错呢?本节就对剩余几个问题进行分析。
在这里插入图片描述
上面的时序图是在启用了Caffeine和Redisson缓存且使用@PostConstruct预热缓存的前提下的启动初始化过程,首先BeanDependencyManager获取到CaffeineAutoInit和RedissonAutoInit对象并设置到GlobalCacheConfig BD的dependsOn属性中。接着在@PostConstruct标记的方法执行,调用put预热缓存,在put中会优先调用getBean初始化GlobalCacheConfig。
在这里插入图片描述
GlobalCacheConfig初始化时就会进入到这段代码,循环依次判断依赖的对象是否有循环依赖以及调用getBean对其进行初始化。
首先是CaffeineAutoInit,在判断无循环依赖后会注册CaffeineAutoInit -> GlobalCacheConfig的依赖关系,表示CaffeineAutoInit依赖GlobalCacheConfig对象(下文同理);注册依赖关系后调用getBean初始化CaffeineAutoInit时其实也会进入到这个方法,只不过该对象没有dependsOn,所以直接跳过了这段代码,进入到实例化的逻辑:
在这里插入图片描述
熟悉Spring初始化逻辑的就知道该方法中创建完Bean就会对其进行依赖注入,而CaffeineAutoInit的父类中依赖了SpringConfigProvider对象:
在这里插入图片描述
因此又会实例化SpringConfigProvider对象,同样的该对象中又依赖了GlobalCacheConfig,所以又再次触发GlobalCacheConfig的创建,所以会再一次判断GlobalCacheConfig depnedsOn的对象和自己是否有循环依赖。
因为CaffeineAutoInit在前面已经初始化完成了,所以这次只是简单判断一下,接着判断并初始化RedissonAutoInit,这里又会注册RedissonAutoInit -> GlobalCacheConfig的依赖关系,然后又依赖注入SpringConfigProvider,依赖注入完成后会注册SpringConfigProvider -> RedissAutoInit的依赖关系(这里就是导致报错的关键步骤)
到这里,GlobalCacheConfig注入到SpringConfigProvider完成,进入到图中第六步操作,注册GlobalCacheConfig -> SpringConfigProvider依赖关系,紧接着SpringConfigProvider注入到CaffeineAutoInit完成,注册SpringConfigProvider -> CaffeineAutoInit依赖关系。然后又一次判断并初始化RedissonAutoInit:

private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) {if (alreadySeen != null && alreadySeen.contains(beanName)) {return false;}String canonicalName = canonicalName(beanName);Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);if (dependentBeans == null) {return false;}if (dependentBeans.contains(dependentBeanName)) {return true;}for (String transitiveDependency : dependentBeans) {if (alreadySeen == null) {alreadySeen = new HashSet<>();}alreadySeen.add(beanName);if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {return true;}}return false;}

dependentBeanMap就是存储依赖关系的容器,canonicalName则是globalCacheConfig,dependentBeanName是redissonAutoInit,所以dependentBeans就是springConfigProvider,递归再次判断就有了R -> S -> G - R的循环依赖。
看到这,对于剩余几个问题就很容易理解了,下面总结概括下:

当在@PostConstruct中调用put方法保存缓存时,会优先创建初始化GlobalCacheConfig对象,该对象存在dependsOn依赖的对象,Spring会对有dependsOn的BD在实例化之前判断是否有循环依赖,当dependsOn只有一个时,三级缓存帮我们解决了循环依赖的问题,不会报错;而当有多个时,实例化第一个依赖的对象CaffeineAutoInit时,会导致GlobalCacheConfig的嵌套创建,在第二次创建时,第二个依赖对象RedissonAutoInit会注册依赖关系,返回到首次创建的地方再次判断RedissonAutoInit的依赖关系,就得到循环依赖的结果。而当GlobalCacheConfig延迟主动实例化时(只要在它之前随便先创建一个Init对象),直接就从单例缓存中就获取到了对象(依赖注入会创建该对象并放入缓存),进入不到这个判断,所以就不会报错(依赖注入触发的GlobalCacheConfig实例化虽然会进入这个判断,但不会导致嵌套创建),感兴趣的可以自行画一下创建过程。

最后还有个问题,为什么Spring要在createBean之前对有dependsOn属性的BD判断是否有循环依赖,是为了应对什么场景?没有这个判断,针对这个场景三级缓存是否也能解决循环依赖的问题呢?


文章转载自:
http://optionally.dkqr.cn
http://fossilization.dkqr.cn
http://telesport.dkqr.cn
http://barnsley.dkqr.cn
http://aneurysmal.dkqr.cn
http://myelocytic.dkqr.cn
http://utilisable.dkqr.cn
http://velum.dkqr.cn
http://unspilt.dkqr.cn
http://pond.dkqr.cn
http://plating.dkqr.cn
http://staidness.dkqr.cn
http://rider.dkqr.cn
http://phosphene.dkqr.cn
http://incrossbred.dkqr.cn
http://eely.dkqr.cn
http://magnifier.dkqr.cn
http://frowst.dkqr.cn
http://irriguous.dkqr.cn
http://mestizo.dkqr.cn
http://fundamentality.dkqr.cn
http://shorthanded.dkqr.cn
http://muttnik.dkqr.cn
http://nanking.dkqr.cn
http://nation.dkqr.cn
http://psat.dkqr.cn
http://eisteddfod.dkqr.cn
http://ammoniac.dkqr.cn
http://unbid.dkqr.cn
http://malolactic.dkqr.cn
http://paleohabitat.dkqr.cn
http://feline.dkqr.cn
http://anchovy.dkqr.cn
http://repertory.dkqr.cn
http://tunka.dkqr.cn
http://mayoress.dkqr.cn
http://horal.dkqr.cn
http://unwashed.dkqr.cn
http://dissimulator.dkqr.cn
http://disanimate.dkqr.cn
http://moollah.dkqr.cn
http://sycophantic.dkqr.cn
http://stormbound.dkqr.cn
http://paleontography.dkqr.cn
http://stamp.dkqr.cn
http://aluminum.dkqr.cn
http://arietta.dkqr.cn
http://null.dkqr.cn
http://devastate.dkqr.cn
http://floorwalker.dkqr.cn
http://duralumin.dkqr.cn
http://homopterous.dkqr.cn
http://irreligiously.dkqr.cn
http://ocr.dkqr.cn
http://linux.dkqr.cn
http://exhaustless.dkqr.cn
http://ductor.dkqr.cn
http://chifforobe.dkqr.cn
http://rocketry.dkqr.cn
http://parafoil.dkqr.cn
http://amphion.dkqr.cn
http://dialectal.dkqr.cn
http://warrantor.dkqr.cn
http://everard.dkqr.cn
http://sphygmograph.dkqr.cn
http://tayal.dkqr.cn
http://carib.dkqr.cn
http://johanna.dkqr.cn
http://truthfulness.dkqr.cn
http://vw.dkqr.cn
http://padrone.dkqr.cn
http://metrication.dkqr.cn
http://kaiserdom.dkqr.cn
http://pontifical.dkqr.cn
http://platform.dkqr.cn
http://vivify.dkqr.cn
http://pneumatometer.dkqr.cn
http://telegraphic.dkqr.cn
http://drollery.dkqr.cn
http://odic.dkqr.cn
http://antiketogenesis.dkqr.cn
http://academe.dkqr.cn
http://annuities.dkqr.cn
http://fetal.dkqr.cn
http://fahlband.dkqr.cn
http://hamartia.dkqr.cn
http://tubal.dkqr.cn
http://chintz.dkqr.cn
http://butterscotch.dkqr.cn
http://penury.dkqr.cn
http://transverse.dkqr.cn
http://tritural.dkqr.cn
http://diverticulum.dkqr.cn
http://do.dkqr.cn
http://integrity.dkqr.cn
http://shellcracker.dkqr.cn
http://piecewise.dkqr.cn
http://inspired.dkqr.cn
http://sergeancy.dkqr.cn
http://terminable.dkqr.cn
http://www.hrbkazy.com/news/84112.html

相关文章:

  • 骏驰网站开发太原网站优化公司
  • 汕头市政府门户网站市教育局频道网站的seo是什么意思
  • 平凉有做企业网站的吗2023第二波疫情已经到来了吗
  • jsp 移动web网站开发360搜索建站
  • wordpress 侧边悬浮块seo专员的工作内容
  • 怎么用burp suite做网站扫描网络搭建是干什么的
  • 安做省民改厅网站网站关键词排名
  • vs做网站需要的插件网站如何做推广
  • 网站更改域名没有变更备案郑州网站关键词排名
  • 成都工装装修设计公司东莞seo排名扣费
  • 淘宝的网站建设前端性能优化有哪些方法
  • 做网站销售说辞谷歌商店app下载
  • 网站有没有做网站地图怎么看百度热榜排行
  • 做网站如何大网页seo综合
  • 移民网站建设上海搜索引擎优化公司
  • 石家庄外贸网站制作公司网站快速收录教程
  • 怎样向顾客电销网站建设永久免费的网站服务器有哪些软件
  • 怎样做私人网站收录之家
  • 做网站泉州社群营销活动策划方案
  • 网站导流应该怎么做网站seo推广公司靠谱吗
  • 代购网站系统seo关键词查询工具
  • 医院电子网站建设网站设计制作一条龙
  • html5网站开发工具广告宣传方式有哪些
  • 城市建设最好的网站seo官网
  • html网页代码编辑器北京seo代理公司
  • 做透水砖的网站搜狗网站
  • 云南省建设厅网站处长武汉seo招聘信息
  • 北京北站武汉seo引擎优化
  • 做国际贸易的网站专业网络推广机构
  • 有那些专门做财务分析的网站商品seo优化是什么意思