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

网站建设是广告吗网站开发实用技术2.8.5

网站建设是广告吗,网站开发实用技术2.8.5,怎样建设网站优化,oa官网下载总结#xff1a;Spring创建Bean循环依赖问题与Lazy注解使用详解 一前提知识储备#xff1a;1.Spring Bean生命周期机制#xff08;IOC#xff09;2.Spring依赖注入机制#xff08;DI#xff09;#xff08;1#xff09;Autowired注解标注属性set方法注入#xff08;2Spring创建Bean循环依赖问题与Lazy注解使用详解 一·前提知识储备1.Spring Bean生命周期机制IOC2.Spring依赖注入机制DI1Autowired注解标注属性set方法注入2Autowired注解标注属性注入3Autowired注解标注构造方法注入也可用于存在多个构造方法时手动指明Spring框架使用哪个构造方法创建Bean 3.了解一定的JVM类加载原理机制1第一次使用new关键字调用类构造方法创建对象时会触发类加载机制然后再执行类实例化机制2每创建一个对象就会触发类实例化机制一次注意不是类加载机制3先产生一个对象的内存地址再调用类的 clinit方法由编译器自动生成用于初始化静态变量和执行静态初始化块的代码最后才执行类的构造方法。4因此一个对象的内存地址可以在构造方法结束之前暴露出来。但Spring中所谓的提前暴露bean对象地址都是指构造方法结束之后暴露而不是构造方法结束之前暴露 4.Lazy注解使用1使用地方类、方法、构造方法、方法参数、属性字段。必须标注在IOC容器管理的bean上才会生效否则无效果2功能作用Springboot项目启动时懒加载Bean。即只会分配对象地址并暴露在IOC容器里面但不会立即执行该Bean的实例化操作构造方法3标注在类上示例延迟创建4标注在方法上示例延迟注入5标注在构造方法参数上示例延迟注入。直接标注在构造方法上面没效果加在构造方法参数上才有效果6标注在属性字段上示例 二·什么是Spring Bean循环依赖问题1.类A中存在类B属性类B中存在类C属性类C中存在类A属性等类似情况2.类A中存在类A属性等类似情况3.Spring项目启动会报异常提示 三·如何解决Spring Bean循环依赖方案一尽量避免双向依赖根本上解决设计时尽量避免双向依赖因为双向依赖很容易导致循环依赖的发生。推荐方案二使用构造函数注入 Lazy注解推荐方案三使用字段属性注入 application.yml配置方案四使用字段属性注入 Lazy注解推荐 四·Spring解决循环依赖的底层原理概述1.三级缓存容器2.为什么Bean 都已经实例化了还需要一个生产 Bean 的ObjectFactory工厂呢3.三级缓存容器工作流程示例假设现在需要实例化两个对象A、B1不存在循环依赖、或者存在循环依赖但不存在AOP操作2存在循环依赖、存在AOP操作 4.为什么要再包装一层ObjectFactory对象存入三级缓存呢说是为了解决Bean对象存在AOP代理情况那么直接生成代理对象半成品Bean放入二级缓存中这不就可以省略三级缓存了吗所以这使用三级缓存的意义在哪里5.使用构造器注入造成的循环依赖三级缓存机制无法自动解决6.为什么构造器注入配合Lazy注解就能解决循环依赖问题呢7·参考文献链接 一·前提知识储备 1.Spring Bean生命周期机制IOC 注意bean实例化就是指调用构造方法创建bean的过程 参考详情文献 https://blog.csdn.net/riemann_/article/details/118500805 2.Spring依赖注入机制DI 参考详情文献 https://juejin.cn/post/6857406008877121550#heading-17 1Autowired注解标注属性set方法注入 Component public class Dog {// 私有成员变量private Cat cat;// 使用Autowired注解标注setter方法Autowiredpublic void setCat(Cat cat) {this.cat cat;}// 其他业务逻辑... }2Autowired注解标注属性注入 Component public class Dog {Autowiredprivate Cat cat; }3Autowired注解标注构造方法注入也可用于存在多个构造方法时手动指明Spring框架使用哪个构造方法创建Bean Component public class Dog {private Cat cat;Autowiredpublic Dog(Cat cat) {this.cat cat;} }3.了解一定的JVM类加载原理机制 参考详情文献 https://blog.csdn.net/weixin_48033662/article/details/135246047 1第一次使用new关键字调用类构造方法创建对象时会触发类加载机制然后再执行类实例化机制 2每创建一个对象就会触发类实例化机制一次注意不是类加载机制 3先产生一个对象的内存地址再调用类的 clinit方法由编译器自动生成用于初始化静态变量和执行静态初始化块的代码最后才执行类的构造方法。 4因此一个对象的内存地址可以在构造方法结束之前暴露出来。但Spring中所谓的提前暴露bean对象地址都是指构造方法结束之后暴露而不是构造方法结束之前暴露 示例代码如下 public class Example {private String value;private Example next;public Example(String value) {// 开启新线程并让其尝试访问this.valuenew Thread(() - {//将当前对象内存地址赋给next属性提前暴露当前对象地址System.out.println(异步线程next next);System.out.println(新线程 this.value);}).start();//将当前对象内存地址赋给next属性提前暴露当前对象地址next this;System.out.println(主线程next next);// 睡眠一段时间模拟初始化耗时操作try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}this.value value;System.out.println(构造方法内部value已初始化为 this.value);}public static void main(String[] args) {Example example new Example(Hello, World!);// 此时example引用已经可以获取但value字段还未初始化System.out.println(example example);} }4.Lazy注解使用 1使用地方类、方法、构造方法、方法参数、属性字段。必须标注在IOC容器管理的bean上才会生效否则无效果 Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.FIELD}) Retention(RetentionPolicy.RUNTIME) Documented public interface Lazy {/*** Whether lazy initialization should occur.*/boolean value() default true;}2功能作用Springboot项目启动时懒加载Bean。即只会分配对象地址并暴露在IOC容器里面但不会立即执行该Bean的实例化操作构造方法 注意 1简述虽然会创建该类的一个对象但是不会执行该对象的构造方法 2没有标注该注解或者进行特定配置时Springboot项目启动时会默认将扫描范围内的所有Bean进行实例化操作既创建该类对象又执行该对象的构造方法 3标注在类上示例延迟创建 Lazy Component public class Cat {private String name;private int age;public Cat() {System.out.println(Cat无参构造方法执行);} }4标注在方法上示例延迟注入 注意Lazy注解 Configuration注解同时标注在类上会作用所有Bean注册的类实例 Configuration public class IocConfig {LazyBeanpublic Dog dog(){return new Dog();} }5标注在构造方法参数上示例延迟注入。直接标注在构造方法上面没效果加在构造方法参数上才有效果 Component public class Cat {private Dog dog;Autowiredpublic Cat(Lazy Dog dog) {this.dog dog;} }6标注在属性字段上示例 Component public class Cat {LazyAutowiredprivate Dog dog; }二·什么是Spring Bean循环依赖问题 1.类A中存在类B属性类B中存在类C属性类C中存在类A属性等类似情况 示例代码 类A Component public class A {Autowiredprivate B b; }类B Component public class B {Autowiredprivate C c; }类C Component public class C {Autowiredprivate A a; }2.类A中存在类A属性等类似情况 示例代码 Component public class A {Autowiredprivate A a; }3.Spring项目启动会报异常提示 三·如何解决Spring Bean循环依赖 方案一尽量避免双向依赖根本上解决设计时尽量避免双向依赖因为双向依赖很容易导致循环依赖的发生。推荐 方案二使用构造函数注入 Lazy注解推荐 1当有两个类互相依赖时只要在任意一个类的构造方法上将另一方参数标注Lazy注解即可打破循环引用当然两个类构造方法互相都加也行 2若很多个类才构成循环依赖则建议直接将每个类的构造方法上对方参数都标注Lazy注解否则你就一个个去分析循环依赖然后再单个加Lazy注解吧 注意构造函数注入是解决循环依赖问题的最佳方式之一因为它能够保证Bean在实例化时所有依赖已经注入。 示例代码 Component public class Cat {private Dog dog;/*** 构造方法注入属性对象时被标注Lazy注解的参数对象并不会直接触发Dog类的实例化操作* 而是会先放入一个dog的代理对象在这里当后面该dog的代理对象被第一次调用时才会触发Dog的实例化操作* 但是生成的实例化对象并不会替换原本的代理对象只会将实例化对象注入代理对象里面。* 代理对象在其内部维护对实际实例的引用在后续每次调用时代理对象都会将请求转发给已经实例化的原生对象并返回原生对象的方法执行结果* param dog*/Autowiredpublic Cat(Lazy Dog dog) {//注意这里不能在构造方法里面调用dog对象一旦调用就会立即触发Dog的实例化操作this.dog dog;} }Component public class Dog {private Cat cat;//只要保证一方加了Lazy注解就行Autowiredpublic Dog(Lazy Cat cat) {this.cat cat;} }方案三使用字段属性注入 application.yml配置 application.yml配置如下 #允许Spring循环引用配置默认是关闭的 spring:main:allow-circular-references: true1开启后Springboot会主动尝试利用三级缓存机制来打破循环引用。如果实在打破不了就会抛循环引用异常让用户自己解决可以配合Lazy注解解决 2一般使用Autowired注入属性的循环依赖都可以被Springboot主动打破 3Spring无法解决单纯由构造器注入导致的循环依赖因为Java语言本身的特性决定了构造器调用必须在一个实例化阶段完成无法通过延后注入的方式打破循环可以配合Lazy注解解决 4非单例bean造成的循环引用Spring也无法自动解决 代码示例 Component public class Cat {Autowiredprivate Dog dog;//手动指明使用哪个构造方法创建beanAutowiredpublic Cat() {System.out.println(Cat无参构造方法执行);} }Component public class Dog {Autowiredprivate Cat cat;Autowiredpublic Dog() {System.out.println(Dog无参构造方法执行);} }方案四使用字段属性注入 Lazy注解推荐 1当有两个类互相依赖时只要在任意一个类中另一方的属性字段上标注Lazy注解即可打破循环引用当然两个类相都加也行 2若很多个类才构成循环依赖则建议直接将每个类的另一方属性字段都标注Lazy注解否则你就一个个去分析循环依赖然后再单个加Lazy注解吧 代码示例 Component public class Cat {LazyAutowiredprivate Dog dog;Autowiredpublic Cat() {System.out.println(Cat无参构造方法执行);} }Component public class Dog {LazyAutowiredprivate Cat cat;Autowiredpublic Dog() {System.out.println(Dog无参构造方法执行);} }四·Spring解决循环依赖的底层原理概述 1.三级缓存容器 public class DefaultSingletonBeanRegistry ... {//1、最终单例Bean容器里面bean都已经完成了实例化、属性注入、初始化称之为一级缓存MapString, Object singletonObjects new ConcurrentHashMap(256);//2、早期Bean单例池缓存半成品对象完成了实例化但未完成属性注入、未执行初始化 init 方法且当前对象已经被其他对象引用了称之为二级缓存MapString, Object earlySingletonObjects new ConcurrentHashMap(16);//3、单例Bean的工厂池缓存半成品对象完成了实例化但未完成属性注入、未执行初始化 init 方法对象未被引用使用时在通过工厂创建Bean称之为三级缓存MapString, ObjectFactory? singletonFactories new HashMap(16); }2.为什么Bean 都已经实例化了还需要一个生产 Bean 的ObjectFactory工厂呢 这跟循环依赖期间存在AOP操作有关 1若不存在循环依赖、或者存在循环依赖但没有AOP操作时ObjectFactory的getObject()方法返回的是原本bean实例对象 2若存在循环依赖且存在AOP操作时ObjectFactory的getObject()方法返回的是原本bean实例的代理对象提前创建代理对象原本Spring的设计模式是bean实例化、属性注入、初始化之后再创建代理对象的但这种特殊情况为了解决循环依赖只能提前创建。因此Spring框架在极端情况下可能出现bean后置处理器方法在属性注入、初始化方法前执行但问题也能解决 3.三级缓存容器工作流程示例假设现在需要实例化两个对象A、B 1不存在循环依赖、或者存在循环依赖但不存在AOP操作 1.先从一级、二级、三级缓存容器找对象A发现没有 2.执行A的构造方法进行实例化但未执行属性注入、初始化操作PostConstructA 只是一个半成品。 3.将早期的A暴露出去放到三级缓存容器singletonFactories中bean对象会被ObjectFactory包装起来 4.A进行属性注入发现没有依赖其他未创建的对象 5.A进行初始化操作PostConstruct完成bean创建工作 6.然后会调用addSingleton方法将自己丢到一级缓存中并将自己从二级、三级缓存中移除实际只有三级缓存容器有对象 7.再按照上述步骤创建B对象从步骤1开始 ......2存在循环依赖、存在AOP操作 1.先从一级、二级、三级缓存容器找对象A发现没有 2.实例化A此时 A 还未完成属性填充和初始化方法PostConstruct的执行A 只是一个半成品。 3.提前暴露A引用为 A 创建一个 Bean 工厂并放入到 singletonFactories 中。 4.属性注入A发现 A 需要注入 B 对象但是一级、二级、三级缓存均为发现对象 B。 5.实例化B此时 B 还未完成属性填充和初始化方法PostConstruct的执行B 只是一个半成品。 6.提前暴露B引用为 B 创建一个 Bean 工厂并放入到 singletonFactories 中。 7.属性注入B发现 B 需要注入 A 对象此时在一级、二级未发现对象 A但是在三级缓存中发现了对象 A从三级缓存中得到对象 A 并将对象 A 放入二级缓存中同时删除三级缓存中的对象 A。注意此时的 A 还是一个半成品并没有完成属性填充和执行初始化方法 然后将对象 A 注入到对象 B 中对象 B 完成属性填充 8.执行B初始化方法B对象彻底创建完成。 9.将B对象放入到一级缓存中同时删除三级缓存中的对象 B。此时对象 B 已经是一个成品 10.对象 A 得到对象 B将对象 B 注入到对象 A 中对象 A 完成属性填充。对象 A 得到的是一个完整的对象 B 11.执行A初始化方法A对象彻底创建完成 12.将A对象放入到一级缓存中同时删除二级缓存中的对象 A。此时对象 A 已经是一个成品4.为什么要再包装一层ObjectFactory对象存入三级缓存呢说是为了解决Bean对象存在AOP代理情况那么直接生成代理对象半成品Bean放入二级缓存中这不就可以省略三级缓存了吗所以这使用三级缓存的意义在哪里 1正常情况下没有循环依赖 1-1Spring都是在完全创建好Bean之后才创建对应的代理对象 2为了处理循环依赖Spring有三种选择 2-1不管有没有循环依赖直接将半成品bean对象放入二级缓存用于解决循环依赖问题。会导致无法注入AOP代理对象只能是原生bean实例对象 2-2不管有没有循环依赖都提前创建好代理对象并将代理对象放入二级缓存出现循环依赖时其他对象直接就可以取到代理对象并注入。会导致无法注入原生bean实例对象只能是AOP代理对象 2-3加一个中间层只有出现循环依赖且存在AOP操作时才会提前生成代理对象其他情况下都是返回原生bean实例对象。这样就极大可能保证Spring按照原本AOP代理设计模式进行创建bean且又能解决循环依赖问题 注意虽然加一个中间层看似极大的兼顾了两种情况。但Spring框架在极端情况下还是可能出现bean后置处理器方法在属性注入、初始化方法前执行但该问题也能通过合理手段解决 5.使用构造器注入造成的循环依赖三级缓存机制无法自动解决 因为构造器循环依赖是发生在bean实例化阶段此时连bean的构造方法都没执行完早期对象都无法创建出来。因此也无法放到三级缓存。三级缓存只能是在bean实例化之后才能起到作用 6.为什么构造器注入配合Lazy注解就能解决循环依赖问题呢 1示例代码 Component public class Cat {private Dog dog;/*** 构造方法注入属性对象时被标注Lazy注解的参数对象并不会直接触发Dog类的实例化操作* 而是会先放入一个dog的代理对象在这里当后面该dog的代理对象被第一次调用时才会触发Dog的实例化操作* 但是生成的实例化对象并不会替换原本的代理对象只会将实例化对象注入代理对象里面。* 代理对象在其内部维护对实际实例的引用在后续每次调用时代理对象都会将请求转发给已经实例化的原生对象并返回原生对象的方法执行结果* param dog*/Autowiredpublic Cat(Lazy Dog dog) {//注意这里不能在构造方法里面调用dog对象一旦调用就会立即触发Dog的实例化操作this.dog dog;} }2使用构造器注入 Lazy注解解决循环依赖的工作流程示例一句话Lazy 注解是通过建立一个中间代理层来破解循环依赖的 1.从一、二、三级缓存总找不到cat对象开始实例化cat对象 2.由于Cat构造器参数dog上标注了Lazy注解因此Spring执行构造方法时会创建一个代理对象赋给dog属性 3.cat对象成功创建实例对象放入三级缓存里面 4.cat对象再执行属性注入、初始化操作完成最终bean创建 5.cat对象最后放入单例池里面一级缓存删除二、三级缓存里面的cat对象 6.当cat对象的dog属性被第一次调用时dog此时是代理对象会触发Dog类的实例化操作生成实例化对象dog2 7.dog2对象再执行属性注入、初始化方法完成最终bean创建放入单例池一级缓存 8.Spring最后再将dog2对象注入到cat对象的dog属性的代理对象里面 生成的实例化对象并不会替换原本的代理对象只会将实例化对象注入代理对象里面。代理对象在其内部维护对实际实例的引用 在后续每次调用时代理对象都会将请求转发给已经实例化的原生对象并返回原生对象的方法执行结果7·参考文献链接 Spring 解决循环依赖必须要三级缓存吗 Spring循环依赖解决方案 Spring使用三级缓存解决循环依赖 spring中怎么解决循环依赖的问题 Spring系列第28篇Bean循环依赖详解
http://www.dnsts.com.cn/news/133682.html

相关文章:

  • 免费网站新域名专业做高端网站
  • 网站建设-部署与发布的题目企业名录查询器免费版
  • 做网站分页怎么做免费网站教程
  • 做淘宝客网站php百度云虚拟主机如何建设网站
  • 做网站卖东西赚钱么软件开发培训班机构
  • 免费发布的网站如何做家居网站
  • 别人做的网站怎么安全放在我的公司做游戏交易网站有哪些
  • 访问中国建设银行网站如何删除网站后台的文章
  • 大学新校区建设网站超级优化大师
  • 小微企业做网站网站制作培训一般要多少钱
  • 协会网站开发金坛常州做网站
  • 网站做投票thinkphp企业网站模板下载
  • 中国建设银行贵州省分行网站陕西省建设执业注册中心网站
  • 网站如何做cdn集约化网站群建设情况
  • 百度做网站吗网站建设创新互联
  • 网站如何做修改密码的相关验证遵义城乡和住房建设厅网站
  • 网站new图标计算机网页怎么制作
  • 北京京西建设集团网站网站架构包含哪几个部分
  • 网站播放器源码飞色网站商城怎么做
  • 做网站运作国珍网络推广服务费会计账务处理
  • 马和人做人和牛做网站网站后台fpt
  • 南宁网站建设_seo优化服务公司东莞品牌网站设计
  • 哪个协会要做网站建设啊关于网页制作
  • 正规网站模板设计想做广告行业怎么入手
  • 网站个性化制作建设工作室
  • 大连市城市建设投资集团网站中国室内设计联盟网站
  • 网站名和域名能一样吗设计师需要了解的网站
  • 做h网站风险电脑端网页设计尺寸
  • 徐州网站定制深圳布吉建网站公司
  • 申通e物流的网站建设合肥建设监理协会网站