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

微网站建设教程云空间的网站

微网站建设教程,云空间的网站,seo外贸仿牌网站换域名,关键词工具有哪些spring三级缓存以及Async产生循环引用spring三级缓存介绍三级缓存解除循环引用原理源码对应1、获取A#xff0c;从三级缓存中获取#xff0c;没有获取到2、构造A#xff0c;将A置入三级缓存构造A(创建A实例)置入缓存3、注入属性#xff0c;构造B扫描缓存实例的相关信息注入… spring三级缓存以及Async产生循环引用spring三级缓存介绍三级缓存解除循环引用原理源码对应1、获取A从三级缓存中获取没有获取到2、构造A将A置入三级缓存构造A(创建A实例)置入缓存3、注入属性构造B扫描缓存实例的相关信息注入属性4、获取B从三级缓存中没有获取到5、构造B将B置入三级缓存6、注入属性构造A7、获取A三个缓存中三级缓存命中8、创建B实例后续步骤9、B构造完成实例放入一级缓存二级三级缓存移除10、创建A实例后续步骤11、A构造完成实例放入一级缓存二级三级缓存移除Async导致三级缓存没有解除循环引用复现测试类描述备注启动测试原因分析解决方法参考spring三级缓存介绍 三级缓存解除循环引用原理 A B A 一级缓存 singletonObjects 二级缓存 earlySingletonObjects 三级缓存 singletonFactories 1、获取A从三级缓存中获取没有获取到 2、构造A将A置入三级缓存 3、注入属性构造B 4、获取B从三级缓存中没有获取到 5、构造B将B置入三级缓存 6、注入属性构造A 7、获取A从三级缓存中获取一级没有、二级没有、三级存在。此时通过从三级的BeanFactory构造实例对象放入二级缓存移除三级缓存 8、创建B实例后续步骤 9、B构造完成实例放入一级缓存二级三级缓存移除 10、创建A实例后续步骤 11、A构造完成实例放入一级缓存二级三级缓存移除 源码对应 springboot 2.5.6 1、获取A从三级缓存中获取没有获取到 // AbstractBeanFactory#doGetBean 256行 protected T T doGetBean(String name, Nullable ClassT requiredType, Nullable Object[] args, boolean typeCheckOnly)throws BeansException { String beanName transformedBeanName(name); Object beanInstance;// 从三个缓存中依次获取注意方法点进去allowEarlyReference是true Object sharedInstance getSingleton(beanName);...2、构造A将A置入三级缓存 构造A(创建A实例) // AbstractAutowireCapableBeanFactory#doCreateBean 582行 protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Nullable Object[] args)throws BeanCreationException { // Instantiate the bean. BeanWrapper instanceWrapper null; if (mbd.isSingleton()) {instanceWrapper this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper null) { // 这里会通过构造函数创建Bean实例instanceWrapper createBeanInstance(beanName, mbd, args); } //省略代码...置入缓存 // AbstractAutowireCapableBeanFactory#doCreateBean 613行 //省略代码... boolean earlySingletonExposure (mbd.isSingleton() this.allowCircularReferences isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) {if (logger.isTraceEnabled()) {logger.trace(Eagerly caching bean beanName to allow for resolving potential circular references);}// 这里会把生成beanName的BeanFactory置入三级缓存addSingletonFactory(beanName, () - getEarlyBeanReference(beanName, mbd, bean)); } //省略代码...3、注入属性构造B 扫描缓存实例的相关信息 InitDestroyAnnotationBeanPostProcessor会解析缓存类中PostStruct和PreDestroy等相关信息 CommonAnnotationBeanPostProcessor会解析缓存类中Recource、WebServiceRef、PostStruct和PreDestroy等相关信息 AutowiredAnnotationBeanPostProcessor会解析缓存类中Autowired、Value、Inject等相关信息 // AbstractAutowireCapableBeanFactory#doCreateBean 594行 //省略代码... synchronized (mbd.postProcessingLock) {if (!mbd.postProcessed) {try {// 解析缓存注解相关信息applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,Post-processing of merged bean definition failed, ex);}mbd.postProcessed true;} } //省略代码... 注入属性 // AbstractAutowireCapableBeanFactory#doCreateBean 619行 //省略代码... try {// 这里会将注入对应的属性populateBean(beanName, mbd, instanceWrapper);exposedObject initializeBean(beanName, exposedObject, mbd); } //省略代码...// AbstractAutowireCapableBeanFactory#populateBean 1431行 //省略代码... // 这里会依次遍历 如果是Resource会在CommonAnnotationBeanPostProcessor中触发注入 // 如果是Autowired则会在AutowiredAnnotationBeanPostProcessor中触发注入 for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {PropertyValues pvsToUse bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);if (pvsToUse null) {if (filteredPds null) {filteredPds filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}pvsToUse bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);if (pvsToUse null) {return;}}pvs pvsToUse; } //省略代码...4、获取B从三级缓存中没有获取到 5、构造B将B置入三级缓存 6、注入属性构造A 上面三个其实类似同前面三步骤差不多 7、获取A三个缓存中三级缓存命中 // AbstractBeanFactory#doGetBean 256行 入口 // DefaultSingletonBeanRegistry#getSingleton 150 // 此时一级缓存和二级缓存里面都没有三级缓存在第二步里面放进去了此时能拿到对应的ObjectFactory //通过它可以获取对应的实例。然后将实例放入二级缓存将三级缓存中对应的BeanName移除 protected Object getSingleton(String beanName, boolean allowEarlyReference) {Object singletonObject this.singletonObjects.get(beanName);if (singletonObject null isSingletonCurrentlyInCreation(beanName)) {singletonObject this.earlySingletonObjects.get(beanName);if (singletonObject null allowEarlyReference) {synchronized (this.singletonObjects) {// Consistent creation of early reference within full singleton locksingletonObject this.singletonObjects.get(beanName);if (singletonObject null) {singletonObject this.earlySingletonObjects.get(beanName);if (singletonObject null) {ObjectFactory? singletonFactory this.singletonFactories.get(beanName);if (singletonFactory ! null) {singletonObject singletonFactory.getObject();this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}}}return singletonObject; }8、创建B实例后续步骤 Async循环引用触发点 这里属性注入完后剩下bean增强、循环依赖校验、注册DisposableBean 9、B构造完成实例放入一级缓存二级三级缓存移除 // DefaultSingletonBeanRegistry#getSingleton 259行 //省略代码... // 这在执行链路的上面几层。这里判断是否是新的单例如果是则置入缓存(一级缓存)中 if (newSingleton) {addSingleton(beanName, singletonObject); } //省略代码...protected void addSingleton(String beanName, Object singletonObject) { // 放入一级缓存从二级缓存和三级缓存中移除synchronized (this.singletonObjects) {this.singletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);} } 10、创建A实例后续步骤 11、A构造完成实例放入一级缓存二级三级缓存移除 逻辑基本同上 Async导致三级缓存没有解除循环引用 复现 测试类 Service Slf4j public class AService {static {log.info(AService init);}Resourceprivate BService bService;public String a2bService(){return bService.get();}Async(async-2)public void exec(){log.info(aService exec);}}Service Slf4j public class BService {static {log.info(BService init);}Autowiredprivate AService aService;public String get(){return BService 666;}public void exec(){log.info(BService exec);}}描述 这里AService 和BService在同一个目录下也没有被在别的类中注入(如果有一个类把两者都注入了且Bservice先注入此时如果三个类中该类最先注入就会导致Bservice先初始化)。在这种情况下默认就会Aservice先初始化然后在Bservice初始化如此才能复现问题。 如果想要调整类加载顺序可以通过DependsOn(value AService)或者Lazy 备注 别开启懒加载不然启动不会报错。 spring.main.lazy-initializationtrue 启动测试 org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name AService: Bean with name AService has been injected into other beans [BService] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using getBeanNamesForType with the allowEagerInit flag turned off, for example.at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:649)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944)at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145)at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754)at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:434)at org.springframework.boot.SpringApplication.run(SpringApplication.java:338)at com.yichen.casetest.CaseTestApplication.main(CaseTestApplication.java:47)原因分析 在bean实例后续步骤中会对bean增强 // AbstractAutowireCapableBeanFactory#doCreateBean 620行 try {populateBean(beanName, mbd, instanceWrapper);// 初始化bean对Bean增强// 1、invokeAwareMethods// 2、applyBeanPostProcessorsBeforeInitialization// 3、invokeInitMethods// 4、applyBeanPostProcessorsAfterInitializationexposedObject initializeBean(beanName, exposedObject, mbd); }在applyBeanPostProcessorsAfterInitialization中由于使用了异步线程池(用了EnableAsync)使得AsyncAnnotationBeanPostProcessor注入了spring容器它会为原有的bean实例创建CGLIB代理使得最初的bean和实例化后暴露出去的bean不是同一个没有通过循环引用校验抛出了异常。 // AsyncAnnotationBeanPostProcessor的子类 //AbstractAdvisingBeanPostProcessor#postProcessAfterInitialization 86行 // 如果类中有Async会创建代理 if (isEligible(bean, beanName)) {ProxyFactory proxyFactory prepareProxyFactory(bean, beanName);if (!proxyFactory.isProxyTargetClass()) {evaluateProxyInterfaces(bean.getClass(), proxyFactory);}proxyFactory.addAdvisor(this.advisor);customizeProxyFactory(proxyFactory);// Use original ClassLoader if bean class not locally loaded in overriding class loaderClassLoader classLoader getProxyClassLoader();if (classLoader instanceof SmartClassLoader classLoader ! bean.getClass().getClassLoader()) {classLoader ((SmartClassLoader) classLoader).getOriginalClassLoader();}return proxyFactory.getProxy(classLoader); }// AbstractAutowireCapableBeanFactory#doCreateBean 632行 // 循环引用检测 if (earlySingletonExposure) {Object earlySingletonReference getSingleton(beanName, false);if (earlySingletonReference ! null) {if (exposedObject bean) {exposedObject earlySingletonReference;}else if (!this.allowRawInjectionDespiteWrapping hasDependentBean(beanName)) {String[] dependentBeans getDependentBeans(beanName);SetString actualDependentBeans new LinkedHashSet(dependentBeans.length);for (String dependentBean : dependentBeans) {if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {actualDependentBeans.add(dependentBean);}}if (!actualDependentBeans.isEmpty()) {throw new BeanCurrentlyInCreationException(beanName,Bean with name beanName has been injected into other beans [ StringUtils.collectionToCommaDelimitedString(actualDependentBeans) ] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using getBeanNamesForType with the allowEagerInit flag turned off, for example.);}}} }解决方法 1、不用异步线程池自己实现线程池 2、通过lazy、DependsOn调整类加载顺序如果让Bservice先加载就不会出错 3、梳理业务逻辑调整技术实现让AService和Bservice不循环引用 参考 Using Async in a circular dependency will throw a BeanCurrentlyInCreationException
http://www.hkea.cn/news/14366161/

相关文章:

  • 网站加地图标记用VS做的网站怎么连接数据库
  • 网站建设安全服务协议网站制作引擎
  • 企业类网站北京建设信源网站 怎么打不开
  • 专业上海网站建设公司哪家好荥阳做网站优化
  • 提供定制型网站建设东莞网站定制开发
  • 怎样把网站的背景图片263企业邮箱app下载安卓
  • iis 怎么绑定网站二级目录wordpress第二张缩略图
  • 以前老网站wordpress博客类主题
  • 怎么建立和设计公司网站wordpress示例页面在哪删除
  • 网站备案完成后接下来怎么做wordpress扫码提交数据
  • 网站建设维护推广合同wordpress作者权限拿shell
  • win2012 iis配置网站全面了解网站开发
  • 如何用源码搭建网站新网站一直不被收录
  • 佛山百度网站排名优化试用体验网站
  • 烟台市最好的专业做网站的公司老薛主机wordpress
  • 常用的软件下载网站全网营销解决方案
  • seo对网站优化广州信科做网站
  • 肇庆企业做网站flash做网站步骤
  • 旅游管理网站业务模块什么网站可以做名片
  • 网站建设违法行为国外最牛设计网站
  • 深圳网站建设公司官网做原油看哪个网站
  • 网站建设与管理教学视频下载成都公司建网站
  • 优化网站是什么意思把自己的电脑做网站服务器
  • 菠菜源码怎么做网站常德市建设工程造价信息网
  • 网站开发培训价格广州网站建设 推广公司哪家好
  • 网站设计素材图片wordpress建英文网站
  • wordpress打开网站前广告便宜 虚拟主机
  • 宁波网站推广联系方式做网站建设销售员准备什么
  • 如何做全景素材网站如何在外管局网站上做延期
  • 智慧校园登录入口盐城网站优化