c++ 单例模式_Spring Bean注入/单例理解/循环依赖

b492adddb94102395f31020be85c78db.png

理解循环依赖问题,首先明白spring有四种注入方式。

第一种,SET注入

a类中持有b类的引用,并且a类有b的set方法。在bean中添加标签即可注入。实质上是将b实例化,然后调用set方法注入。

 

第二种,构造器注入

a类中持有b类的引用,并且a的构造函数参数中有b。实质上就是通过构造函数注入,创建a对象时要把b对象传进去。

 

第三种,静态工厂

如果有需要静态工厂实例化的类,不能通过静态工厂.方法实现。在bean属性中对应类指向静态工厂,对应方法指向返回实例的方法

c51002e15ce241e6941ee9a252e00842.png

第四种,实例工厂

如果工厂不是静态,需要实例化,就实例化对应工厂,设定factory-bean和factory-method进行方法调用。

8ddc435b7d76580cc29008fbf2d9765c.png

设定三个实体类,StudentA,B,C代码如下,A持有B,B持有C,C持有A

public class StudentA { private StudentB studentB ; public void setStudentB(StudentB studentB) { this.studentB = studentB; } public StudentA() { } public StudentA(StudentB studentB) { this.studentB = studentB; }}

当我通过构造器注入时,会产生BeanCurrentlyInCreationException异常。为什么会出现这种异常,spring如何加载实体?

107159321c400be6537c0971e5260197.png

Spring容器会将每一个正在创建的Bean 标识符放在一个“当前创建Bean池”中,Bean标识符在创建过程中将一直保持在这个池中,因此如果在创建Bean过程中发现自己已经在“当前创建Bean池”里时将抛出BeanCurrentlyInCreationException异常表示循环依赖;而对于创建完毕的Bean将从“当前创建Bean池”中清除掉。

Spring容器先创建单例StudentA,StudentA依赖StudentB,然后将A放在“当前创建Bean池”中,此时创建StudentB,StudentB依赖StudentC ,然后将B放在“当前创建Bean池”中,此时创建StudentC,StudentC又依赖StudentA, 但是,此时Student已经在池中,所以会报错,因为在池中的Bean都是未初始化完的,所以会依赖错误.

解决这个问题,可以用setter注入的方式。

3651f6dea59550a34fe4bc9222ea0d97.png

Spring是先将Bean对象实例化之后,再设置对象属性。所以会先调用他的无参构造函数实例化。每个对象存在一个map中。当遇到依赖,就去map中调用对应的单例对象。

c8cc584db7a015aeb756bdcf395e1e7d.png

一部分源码

另外: 对于“prototype”作用域Bean,Spring容器无法完成依赖注入,因为“prototype”作用域的Bean,Spring容器不进行缓存,因此无法提前暴露一个创建中的Bean。


Spring装配Bean的过程

  1. 实例化;
  2. 设置属性值;
  3. 如果实现了BeanNameAware接口,调用setBeanName设置Bean的ID或者Name;
  4. 如果实现BeanFactoryAware接口,调用setBeanFactory 设置BeanFactory;
  5. 如果实现ApplicationContextAware,调用setApplicationContext设置ApplicationContext
  6. 调用BeanPostProcessor的预先初始化方法;
  7. 调用InitializingBean的afterPropertiesSet()方法;
  8. 调用定制init-method方法;
  9. 调用BeanPostProcessor的后初始化方法;

Spring容器关闭过程

  1. 调用DisposableBean的destroy();
  2. 调用定制的destroy-method方法;
2405caefaf7cea6ee2c99b532273f03c.png

了解了bean默认是单例模式,不由想spring的单例和设计模式单例同一种吗?其实不一样。单例模式是指在一个JVM进程中仅有一个实例,而Spring单例是指一个Spring Bean容器(ApplicationContext)中仅有一个实例。如果有多个Spring容器,可能有多个Bean对象。

spring单例是一种类似注册表实现的方式。利用hashmap,向map中注册和取值,思路类似下面代码

public class Singleton { private static Map map = new HashMap(); static{ Singleton single = new Singleton(); map.put(single.getClass().getName(), single); } //保护的默认构造子 protected Singleton(){} //静态工厂方法,返还此类惟一的实例 public static Singleton getInstance(String name) { if(name == null) { name = Singleton.class.getName(); } if(map.get(name) == null) { try { map.put(name, (Singleton) Class.forName(name).newInstance()); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } return map.get(name); }}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
单例模式是一种常用的设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问该实例。这对于需要共享资源或控制一个唯一对象的情况非常有用。实现单例模式可以通过在类中维护一个私有静态实例变量,并提供一个公有的静态方法来获取该实例。 工厂模式是另一种常用的设计模式,它用于创建对象而不必暴露创建对象的逻辑。该模式通过定义一个工厂类,该类负责创建和返回对象的实例。工厂类可以有多个方法用于创建不同类型的对象,这样可以根据不同的条件和参数来创建不同的对象。 建造者模式也是一种常用的设计模式,它用于创建复杂对象。该模式通过将对象的构造过程分解为一系列步骤来创建对象。每个步骤由一个具体的建造者类负责实现,最终由一个指导者类来指导建造过程。通过使用建造者模式,可以将对象的构造过程和表示细节与具体的客户代码解耦,使得对象的构造更加灵活。 这些常用的设计模式在软件开发中起到了至关重要的作用。单例模式可以确保在整个应用程序中只有一个实例,并保证该实例的访问是线程安全的。工厂模式可以帮助我们创建不同类型的对象,将具体对象的创建逻辑封装在工厂类中,提高了代码的复用性和可维护性。建造者模式可以将对象的创建过程与表示细节解耦,使得代码更加灵活和可拓展。 总之,这些常用的设计模式在软件开发中发挥着重要的作用,可以提高代码的可读性、可维护性和可拓展性。熟练应用这些设计模式可以帮助我们更好地组织和设计代码,提高开发效率和代码质量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值