Spring获取单例getSingleton(1)
Spring 获取 单例
2023-09-14 09:00:26 时间
spring获取单例首先是从缓存去找,如果找不到就要从头开始bean的加载过程,spring中主要通过getSingleton的重载方法实现单例bean的加载过程
要创建一个bean的单例,首先了解下单例是什么样子的,
public static synchronized Singleton getInstance() { if (single == null) { single = new Singleton(); return single; }
spring创建单例bean主要查看 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry类的getSingleton(String beanName, ObjectFactory
public Object getSingleton(String beanName, ObjectFactory ? singletonFactory) { Assert.notNull(beanName, "beanName must not be null"); //同步 开始创建单例 synchronized (this.singletonObjects) { Object singletonObject = this.singletonObjects.get(beanName); //判断单例是否被创建 如果已经创建则不在重复创建 if (singletonObject == null) { if (this.singletonsCurrentlyInDestruction) { throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while the singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); if (logger.isDebugEnabled()) { logger.debug("Creating shared instance of singleton bean " + beanName + ""); //把当前正在创建的bean记录在缓存中,对循环依赖进行检测 beforeSingletonCreation(beanName); boolean newSingleton = false; boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet Exception try { //使用回调方法 创建单例bean singletonObject = singletonFactory.getObject(); newSingleton = true; catch (IllegalStateException ex) { singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { throw ex; catch (BeanCreationException ex) { if (recordSuppressedExceptions) { for (Exception suppressedException : this.suppressedExceptions) { ex.addRelatedCause(suppressedException); throw ex; finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; //移除缓存中对该bean正在加载的状态 afterSingletonCreation(beanName); if (newSingleton) { //将新创建的bean加入缓存,并且删除加载bean过程中所记录的各种辅助状态 //这些辅助状态主要是在回调方法创建bean时候引入的 addSingleton(beanName, singletonObject); return (singletonObject != NULL_OBJECT ? singletonObject : null); }
现在继续去找创建bean的回调方法
//创建完的beanInstance还不一定不是我们最终需要的bean 还需要加工验证正确性 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
createBean方法里面还是在做一些准备工作,真正的创建bean交给了doCreateBean
@Override protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException { if (logger.isDebugEnabled()) { logger.debug("Creating instance of bean " + beanName + ""); RootBeanDefinition mbdToUse = mbd; //根据指定的BeanDefinition信息 解析bean class 并且存储在BeanDefinition中 Class ? resolvedClass = resolveBeanClass(mbd, beanName); //对已有的bean definition进行克隆 以防一动态解析的class不能存储在合并的bean definition中 //这里说的动态解析的class是指在bean class的定义中使用EL表达式或者自己定义的beanExpressionResolver if (resolvedClass != null !mbd.hasBeanClass() mbd.getBeanClassName() != null){ mbdToUse = new RootBeanDefinition(mbd); mbdToUse.setBeanClass(resolvedClass); try { //验证及准备覆盖的方法 mbdToUse.prepareMethodOverrides(); catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", ex); try { //给beanPostProcessors一个机会返回代理来替代真正的实例 //这里的beanPostProcessors是指InstantiationAwareBeanPostProcessor类型 Object bean = resolveBeforeInstantiation(beanName, mbdToUse); if (bean != null) { return bean; catch (Throwable ex) { throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", ex); //创建bean的过程又交给了doCreateBean,spring中以doxxx开头的方法就是真正干活的方法 Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isDebugEnabled()) { logger.debug("Finished creating instance of bean " + beanName + ""); return beanInstance; }
在这里首先关注下AbstractBeanDefinition类的prepareMethodOverrides方法
public void prepareMethodOverrides() throws BeanDefinitionValidationException { // Check that lookup methods exists. MethodOverrides methodOverrides = getMethodOverrides(); if (!methodOverrides.isEmpty()) { for (MethodOverride mo : methodOverrides.getOverrides()) { prepareMethodOverride(mo); }
protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException { int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName()); if (count == 0) { throw new BeanDefinitionValidationException( "Invalid method override: no method with name " + mo.getMethodName() + " on class [" + getBeanClassName() + "]"); else if (count == 1) { // Mark override as not overloaded, to avoid the overhead of arg type checking. mo.setOverloaded(false); }
spring配置中存在lookup-method和replace-method两个配置功能,这两个配置的加载就是将配置存储在BeanDefinition中的methodOverrides属性里面。功能的实现原理是在bean的实例化的时候如果检测到存在methodOverrides属性,会动态的为当前bean生成代理并使用对应的拦截器为bean做增强处理。
下一篇继续从doCreateBean说起。
虾皮二面:Spring Bean 默认是单例的,如何保证并发安全? Spring 的 Bean 默认都是单例的,某些情况下,单例是并发不安全的,以 Controller 举例,问题根源在于,我们可能会在 Controller 中定义成员变量,如此一来,多个请求来临,进入的都是同一个单例的 Controller 对象,并对此成员变量的值进行修改操作,因此会互相影响,无法达到并发安全(不同于线程隔离的概念,后面会解释到)的效果。 首先来举个例子,证明单例的并发不安全性:
Spring 源码阅读 25:单例 Bean 实例的创建过程(2) 通过本文的分析,终于走到了 Spring 最终把 Bean 实例创建出来的,这个实例会被一个 BeanWrapper 类型的对象包装,并返回到`doCreateBean`方法中。
Spring 源码阅读 17:初始化非懒加载的单例 Bean 本文分析 Spring 上下文初始化过程中, 提前初始化非懒加载的单例 Bean 的过程。这一步算是在容器初始化是进行的创建 Bean 的预热工作。
Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean 七千字长文深刻解读,Spirng中是如何初始化单例bean的,和面试中最常问的Spring是如何解决循环依赖?
阿里特邀专家徐雷Java Spring Boot开发实战系列课程(第18讲):制作Java Docker镜像与推送到DockerHub和阿里云Docker仓库 立即下载
相关文章
- 云享专家倪升武:微服务架构盛行的时代,你需要了解点 Spring Boot
- spring相关面试题
- Spring security 用户,角色,权限,资源
- Spring Boot 项目打成 war 包部署,接口报 404 问题
- 【Spring】@PathVariable 获取带点参数,获取不全
- spring boot: GlobalDefaultExceptionHandler方法内的友好错误提示,全局异常捕获
- Quartz在Spring中动态设置cronExpression (spring设置动态定时任务)------转帖
- Spring+DBUnit+H2----项目单元测试
- 20-spring学习-Spring MVC基本操作
- Spring Boot Dubbo applications.properties 配置清单
- [Spring学习笔记 3 ] spring 注解详解,完全注解,常用注解
- spring 从bean实例中获取对象
- spring bean加载--从缓存中获取bean
- [Java Spring] Built-in page and sorting
- spring boot: filter/interceptor/aop在获取request/method参数上的区别(spring boot 2.3.1)
- 封装一个流水号ID生成器:id-spring-boot-starter
- Spring AOP编程-aspectJ代理方式选择
- spring boot 获取bean
- Spring读源码系列之AOP--06---AopProxy===>spring使用jdk和cglib生成代理对象的终极奥义
- Atitit spring注解事务的demo与代码说明 目录 1.1. Spring框架中,要如何实现事务?有一个注解,@EnableTransactionManagement1 1.2. 事务管理
- Spring+Quartz实现定时任务
- spring cloud --- Ribbon 客户端负载均衡 + RestTemplate + Hystrix 熔断器 [服务保护] ---心得
- 不用被动注入的方式, 主动从 Spring Boot 应用容器中的获取 Bean 的方法
- 005-spring-data-elasticsearch 3.0.0.0使用【三】-spring-data之Spring数据扩展
- Spring提供的@Validated和MethodValidationPostProcessor完成数据校验
- 【java】Spring Boot --spring boot项目整合xxl-job