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

成都哪里做网站备案虚拟主机安装网站

成都哪里做网站备案,虚拟主机安装网站,网站制作技术支持,台州哪家做企业网站比较好一、Async 注解下的循环依赖问题 我们都知道 Spring IOC 单例模式下可以帮助我们解决循环依赖问题#xff0c;比如下面自己依赖自己循环依赖的场景#xff1a; Component public class TestAsync {ResourceTestAsync async;public void test() {System.out.println(t…一、Async 注解下的循环依赖问题 我们都知道 Spring IOC 单例模式下可以帮助我们解决循环依赖问题比如下面自己依赖自己循环依赖的场景 Component public class TestAsync {ResourceTestAsync async;public void test() {System.out.println(test....);} }从容器中获取到该 bean 执行测试方法 public class App {public static void main(String[] args) {ApplicationContext context new AnnotationConfigApplicationContext(com.demo.test);TestAsync testAsync context.getBean(testAsync, TestAsync.class);testAsync.test();}}可以看到正常执行但当我们加上 Async 注解后 Component EnableAsync public class TestAsync {ResourceTestAsync async;Asyncpublic void test() {System.out.println(test....);} }再次执行发现报错了 是不是很奇怪难道代理对象就会有问题吗如果换成 Transactional 呢 Component EnableTransactionManagement public class TestAsync {ResourceTestAsync async;Transactionalpublic void test() {System.out.println(test....);} }再次执行发现可以正常运行 那为什么 Async 会有问题呢其实和我们上篇文章中讲解的 BeanPostProcessor 扩展接口有关这里先说一下解决方法 将依赖注入换成懒加载的方式即可 Component EnableAsync public class TestAsync {ResourceLazyTestAsync async;Asyncpublic void test() {System.out.println(test.... Thread.currentThread().getName());} }可以看到恢复正常了下面从源码角度分析下出现该问题的原因。 如果不了解 BeanPostProcessor 扩展接口可以先看下下面这篇文章 Spring 源码解析 - BeanPostProcessor 扩展接口 二、源码分析 2.1 EnableAsync 当使用 EnableAsync 开启异步支持时会向 Spring 容器中注入AsyncConfigurationSelector.class 类 在该类中selectImports 下根据 adviceMode 选择注入配置类adviceMode 默认为 PROXY会注入 ProxyAsyncConfiguration.class 配置类 在 ProxyAsyncConfiguration.class 配置类下注入了一个 AsyncAnnotationBeanPostProcessor 扩展类 下面看下AsyncAnnotationBeanPostProcessor 扩展类的继承树 AsyncAnnotationBeanPostProcessor 从 BeanPostProcessor 获得bean初始化前后的扩展能力从 ProxyProcessorSupport 获取代理能力。 这里重点看 BeanPostProcessor 扩展在 BeanPostProcessor 中有两个核心的扩展方法如下 public interface BeanPostProcessor {/*** 实例化及依赖注入完成后、bean 初始化方法触发之前执行*/Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;/*** bean 初始化方法触发后执行*/Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;}下面看挨个看AsyncAnnotationBeanPostProcessor中这两个方法干了什么 在AsyncAnnotationBeanPostProcessor没有直接实现 postProcessBeforeInitialization 实现在 AbstractAdvisingBeanPostProcessor 下的 postProcessBeforeInitialization 方法 没有做任何操作直接返回的原 bean 同样 postProcessAfterInitialization 方法也在 AbstractAdvisingBeanPostProcessor 下 在这里实际生成了代理 bean 进行返回。 到这我们需要记住 AsyncAnnotationBeanPostProcessor 的postProcessBeforeInitialization 前通知没有做任何操作 postProcessAfterInitialization 后通知创建了代理实例。 2.2 getEarlyBeanReference 了解过循环依赖的应该知道 Spring 中使用三级缓存来解决循环依赖问题其中实例化 bean 后会首先曝光至第三级缓存中该逻辑在 AbstractAutowireCapableBeanFactory 类的 doCreateBean 方法下 在 doCreateBean 方法下的 populateBean 主要是进行了依赖的注入 在进行依赖注入时会递归尝试从三级缓存中获取 bean 由于这里是循环依赖已经放入了第三级缓存中因此可以命中这快的源码逻辑在 DefaultSingletonBeanRegistry 类下的 getSingleton 方法 这里可以看出三级缓存命中会执行 ObjectFactory.getObject() 方法获取一个早期的实例获取之后存入二级缓存中从前面放入三级缓存可以看出其实是触发的 AbstractAutowireCapableBeanFactory 下的 getEarlyBeanReference 方法 这里会判断是否存在 SmartInstantiationAwareBeanPostProcessor 类型的 BeanPostProcessor 扩展然后尝试使用 getEarlyBeanReference 获取一个早期的实例从前面 AsyncAnnotationBeanPostProcessor 的继承树可以看出并没有实现 SmartInstantiationAwareBeanPostProcessor 因此这里拿到的就是原来的 bean 实例 到这里我们需要记住Spring 单例缓存中存储的是 TestAsync 真正的实例对象。 2.3 initializeBean 在依赖注入后会触发 initializeBean 方法进行 bean 的初始化操作 在 initializeBean 方法中执行初始化前先执行BeanPostProcessors的前置方法并且将前置方法返回的 bean 代替原先创建的 bean 在 bean 初始化后执行BeanPostProcessors的后置方法并将后置方法返回的 bean 代替原先的 bean从上面对 AsyncAnnotationBeanPostProcessor的简单分析得出前置方法没做任何处理后置方法会生成一个代理对象因此initializeBean 方法最终返回的是代理对象 可以看出最后生成的是一个代理对象现在应该就会发现一个问题了在 Spring 单例容器中和依赖注入中的都是 TestAsync 真正的实例而这里返回的是代理实例现在相当于单例的 bean 存在了两个不同的实例。 2.4 判断是否出现重复实例 在回到 doCreateBean 方法下 initializeBean 执行后 如果是单例的话则尝试从容器中获取当前的 beanName 实例由于前面已经曝光到了二级缓存中因此这里可以获取到但容器中的bean实例和当前的 bean实例已经不是一个实例了因此会进入到 else if 中这里获取到该 beanName 所有的依赖通过 removeSingletonIfCreatedForTypeCheckOnly 删除已经创建好的 bean 实例因为单例模式下 Spring 仅允许有一个实例这里可以看下 removeSingletonIfCreatedForTypeCheckOnly 方法的逻辑 这里主要判断 alreadyCreated 中是否存在如果不存在则删除单例缓存中的实例那 alreadyCreated 什么时候放入的呢其实在AbstractAutowireCapableBeanFactory 类的 doGetBean 方法中触发的 markBeanAsCreated 方法 因此 removeSingletonIfCreatedForTypeCheckOnly 方法这里会返回 false在回到 doCreateBean 中继续看由于 removeSingletonIfCreatedForTypeCheckOnly 返回 false 正好符合条件被加入了 actualDependentBeans 集合中再下面如果actualDependentBeans 集合不为空则抛出异常这个异常是不是和之前报错的异样一样 三、为什么 Transactional 不会出现这种问题呢 从上面的分析可以得出结论假如 getEarlyBeanReference 可以获取到代理实例是不是就不会发生后面的问题这恰恰也是 Transactional 情况下的不会出现该问题的关键点。 Transactional 代理使用的是 InfrastructureAdvisorAutoProxyCreator 从 InfrastructureAdvisorAutoProxyCreator的继承树可以看到其继承了 SmartInstantiationAwareBeanPostProcessor 方法。并且在父类 AbstractAutoProxyCreator 中重写了 getEarlyBeanReference 方法 下面可以 debug 一下 AbstractAutowireCapableBeanFactory 中的 getEarlyBeanReference 方法 可以看到这里还是真正的实例对象下面会进到 AbstractAutoProxyCreator 中重写的 getEarlyBeanReference 方法最终进到当前类的 wrapIfNecessary 方法 到这里就已经生成了一个代理类了再回到 AbstractAutowireCapableBeanFactory 中的 getEarlyBeanReference 方法中这时返回的就是代理类了。
http://www.w-s-a.com/news/518083/

相关文章:

  • 网站及单位网站建设情况眉县住房和城市建设局网站
  • 网站是否能够被恶意镜像wordpress占用
  • 经典设计网站网站等保测评怎么做
  • 重庆做网站公司贴吧廊坊公司快速建站
  • 海外贸易在什么网站做怎么排名到百度第一页
  • 线上注册公司是在哪个网站做高仿网站
  • 网站构架图网上推广平台哪个好
  • 公司网站首页图片素材vi设计的目的和意义
  • 网站的需求分析都有哪些内容济南营销型网站建设团队
  • 怎么选择优秀的网站建设公司生鲜网站开发
  • 如何编写网站建设销售的心得网站的权限管理怎么做
  • 网站业务员好做吗无忧网站优化
  • 网站随机代码网站建设费 账务处理
  • 商洛网站建设哪家好网站建设 织梦者
  • 怎么创建收费网站宁夏住房和城乡建设部网站
  • 怎么确认网站是什么语言做的用php和mysql做网站
  • 安徽做网站的公司有哪些星子网络公司
  • 肥西县重点工程建设管理局网站wordpress界面菜单怎么弄
  • 宁夏网站开发设计说明书wordpress主题背景图片
  • 同一个阿里云可以做两个网站吗织梦 帝国 学校网站
  • 城阳网站建设培训网站后台怎么上传文件
  • 重庆茂尔建设集团有限公司网站网页制作教程软件
  • 金湖建设工程质量监督网站高端网站建设公司哪里济南兴田德润实惠吗
  • 站酷设计网站官网入口文字设计seo网站推广工具
  • 专业移动网站建设网站建设软件dw
  • 摄影网站设计思想视觉传达毕业设计作品网站
  • 需要优化的网站有哪些设计装修app
  • 数据型网站建设东莞好的网站国外站建设价格
  • 网络营销方法有哪些举例seo应用领域有哪些
  • 建设银行官方网站官网做网站的专业叫什么