范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

Spring是如何解决循环依赖的?

  1 循环依赖
  你需要我,我需要你就是循环依赖 @Component public A {     @Resource     private B b ; } @Component public B {     @Resource     private A a ; }
  在Spring中使用的三级缓存来解决循环依赖问题,这里的缓存其实就是Map对象 public class DefaultSingletonBeanRegistry {   // 一级缓存:完整完全初始化完成的Bean     /** Cache of singleton objects: bean name to bean instance. */   private final Map singletonObjects = new ConcurrentHashMap<>(256);   // 三级缓存:最终通过ObjectFactory.getObject返回对象   /** Cache of singleton factories: bean name to ObjectFactory. */   private final Map> singletonFactories = new HashMap<>(16);   // 二级缓存   /** Cache of early singleton objects: bean name to bean instance. */   private final Map earlySingletonObjects = new ConcurrentHashMap<>(16);    }    1.1 获取Bean流程public abstract class AbstractBeanFactory   protected  T doGetBean(...) throws BeansException {     // Eagerly check singleton cache for manually registered singletons.     // 进入DefaultSingletonBeanRegistry类     Object sharedInstance = getSingleton(beanName);   } } public class DefaultSingletonBeanRegistry {   public Object getSingleton(String beanName) {     return getSingleton(beanName, true);   }   protected Object getSingleton(String beanName, boolean allowEarlyReference) {     // Quick check for existing instance without full singleton lock     // 先从一级缓存中获取Bean对象       Object singletonObject = this.singletonObjects.get(beanName);     // 如果不存在&当前的Bean没有被正在创建进入if块     if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {       // 从二级缓存中获取Bean对象         singletonObject = this.earlySingletonObjects.get(beanName);       // 如果二级缓存中不存在&允许创建早起对象进入if块         if (singletonObject == null && allowEarlyReference) {         synchronized (this.singletonObjects) {           // Consistent creation of early reference within full singleton lock           // DCL检查             // 从一级缓存中查找             singletonObject = this.singletonObjects.get(beanName);           if (singletonObject == null) {             // 从二级缓存中查找               singletonObject = this.earlySingletonObjects.get(beanName);             if (singletonObject == null) {               // 从三级缓存中获取ObjectFactory对象                 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);               if (singletonFactory != null) {                 singletonObject = singletonFactory.getObject();                 // 调用三级缓存ObjectFactory.getObject返回的对象存入二级缓存中                 this.earlySingletonObjects.put(beanName, singletonObject);                 // 从三级缓存中删除                   this.singletonFactories.remove(beanName);               }             }           }         }       }     }     return singletonObject;   }   }
  当获取一个Bean时会先从缓存中查找是否有相应的Bean。 1.2 依赖对象注入
  1  创建A实例
  2  将A实例(半初始化,属性没有填充)暴露放入缓存中 public abstract class AbstractAutowireCapableBeanFactory {   protected Object doCreateBean(...) throws BeanCreationException {         // Eagerly cache singletons to be able to resolve circular references 	// even when triggered by lifecycle interfaces like BeanFactoryAware.     // 在这里会检查当前是否是单例Bean & 是否允许循环依赖(默认是允许的)可以通过BeanFactoryPostProcessor来改变该值setAllowCircularReferences & 当前的Bean是否正在创建中        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));     if (earlySingletonExposure) {         // 将当前创建出来的Bean(刚刚new出来的对象)将其放入三级缓存中         addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); 	}       }       // 该方法的作用就是为早期创建的对象(没有进行初始化的对象)先创建代理对象。   // 前提你的开启代理功能,如:容器中创建有AbstractAutoProxyCreator类型的Bean对象(一般都是继承该类,其实就是BeanPostProcessor对象)   // 开启代理(@EnableAspectJAutoProxy) 会注册AspectJAwareAdvisorAutoProxyCreator Bean进行代理对象的创建   // 简单说就是:你的提供BeanPostProcessor(一般我们都继承AbstractAutoProxyCreator类)   protected Object getEarlyBeanReference(...) {     Object exposedObject = bean;     if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {       for (BeanPostProcessor bp : getBeanPostProcessors()) {         if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {           SmartInstantiationAwareBeanPostProcessor ibp =(SmartInstantiationAwareBeanPostProcessor) bp;           exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);         }       }     }     return exposedObject;   }   } public class DefaultSingletonBeanRegistry {   protected void addSingletonFactory(...) {     synchronized (this.singletonObjects) {       if (!this.singletonObjects.containsKey(beanName)) {         this.singletonFactories.put(beanName, singletonFactory);         this.earlySingletonObjects.remove(beanName);         this.registeredSingletons.add(beanName);       }     }   } }
  3  填充A实例的属性public abstract class AbstractAutowireCapableBeanFactory {   Object exposedObject = bean;   try {     // 填充A实例属性,也就是在这里后会先再去创建依赖的B实例对象。     populateBean(beanName, mbd, instanceWrapper);     exposedObject = initializeBean(beanName, exposedObject, mbd);   } catch (Throwable ex) {     // ...   }    return exposedObject ;     }
  4  A实例属性依赖B对象
  5  创建B对象实例
  6  填充B实例属性
  7  B实例属性依赖A对象
  8  将上面已经暴露到三级缓存中的A对象注入给B实例
  在获取A对象的时候执行上面27.1中的getSingleton方法,会将三级缓存中A这个半初始化状态的对象移除,将其存入到二级缓存中。
  9  B实例Bean的创建工作继续执行初始化方法public abstract class AbstractAutowireCapableBeanFactory {   Object exposedObject = bean;   try {     // B实例将需要的A对象已经注入了(A暴露的半初始化状态对象)     populateBean(beanName, mbd, instanceWrapper);     // B实例Bean将继续向下执行初始化方法     exposedObject = initializeBean(beanName, exposedObject, mbd);   } catch (Throwable ex) {     // ...   }    return exposedObject ;     }
  B如果需要AOP代理?最终B对象是个代理对象。B到此就完全的初始化完了,B的依赖对象A此时是个半初始化状态的对象
  10  B实例对象保存到一级缓存
  最终B实例创建,初始化都执行完后会将自身加入到一级缓存同时清除二级,三级缓存 public abstract class AbstractBeanFactory {   protected  T doGetBean(...) {     // Create bean instance. 	if (mbd.isSingleton()) {       sharedInstance = getSingleton(beanName, () -> {         try {           return createBean(beanName, mbd, args);         } catch (BeansException ex) { 		}       });       bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);     }       }     } // getSingleton方法 public class DefaultSingletonBeanRegistry {   public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {     synchronized (this.singletonObjects) {       // 从单例池中获取对象         Object singletonObject = this.singletonObjects.get(beanName);       if (singletonObject == null) {         beforeSingletonCreation(beanName); 		try {           singletonObject = singletonFactory.getObject(); 		} catch (IllegalStateException ex) {           //...     		} finally {           afterSingletonCreation(beanName);         }         // 将当前创建的Bean加入单例池中,并且清除相应的二级,三级缓存           addSingleton(beanName, singletonObject);       }       return 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);     }   }   }
  11  A实例Bean创建继续执行
  如果B是被AOP代理的那么此时的A实例注入的B对象就是一个代理对象。
  12  A实例Bean执行初始化方法
  13  A继续执行上面的10步骤 1.3 三级缓存解决的问题
  三级缓存解决问题:循环依赖+AOP问题
  只用一,二级缓存: A创建实例,将其缓存到earlySingletonObjects A填充属性,发现需要B B创建实例,将其缓存到earlySingletonObjects B填充属性,发现需要A 从earlySingletonObjects中找到A填充 B继续执行初始化方法 B创建完成 返回继续将创建的B注入到A中 A继续执行初始化方法 A,B都彼此有了对方,一切正常
  从上面罗列的步骤看似乎很是完美解决了循环依赖问题,接下来我们看看加入AOP的场景
  假如A,B两个对象最终都是要被AOP代理的 A创建实例,将其缓存到earlySingletonObjects A填充属性,发现需要B B创建实例,将其缓存到earlySingletonObjects B填充属性,发现需要A 从earlySingletonObjects中找到A填充(此时B中填充的对象是个原始对象) B继续执行初始化方法 B通过BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建代理对象 B创建完成,最终B是个代理的对象 返回继续将创建的B注入到A中(此时A中注入的B对象是个代理对象) A继续执行初始化方法 A通过BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建代理对象
  执行到这里,A中依赖的B是代理对象没有问题,但是B中依赖的A对象是原始对象;这就不正确了应该依赖的A也必须是代理对象才是。
  引入三级缓存:
  三级缓存引入了ObjectFactory对象,在获取对象的时候,是调用ObjectFactory#getObject方法。
  而这个getObject方法的实现实际执行的是getEarlyBeanReference方法,再来回顾下:
  在创建实例时先将其存入三级缓存中: public abstract class AbstractAutowireCapableBeanFactory {   protected Object doCreateBean(...) throws BeanCreationException {     // 判断是否是单例 & 是否允许循环依赖 & 当前的Bean是否正在创建中       boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));     if (earlySingletonExposure) {       // 这里的第二个参数就是通过函数式接口实现的ObjectFactory          addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));     }         }     } // 当前的Bean是否正在创建,是在哪里设置的?AbstractBeanFactory#doGetBean.getSingleton中设置的 if (mbd.isSingleton()) {   sharedInstance = getSingleton(beanName, () -> {     try {       return createBean(beanName, mbd, args);     } catch (BeansException ex) {     }   });   bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }
  getEarlyBeanReference方法就是提前创建代理对象 public abstract class AbstractAutowireCapableBeanFactory {   // 在该方法中执行SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference   protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {     Object exposedObject = bean;     if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {       for (BeanPostProcessor bp : getBeanPostProcessors()) {         if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {           SmartInstantiationAwareBeanPostProcessor ibp =(SmartInstantiationAwareBeanPostProcessor) bp;           exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);         }       }     }     return exposedObject;   }     }
  如果开启了AOP代理后 public abstract class AbstractAutoProxyCreator {   @Override   public Object getEarlyBeanReference(Object bean, String beanName) {       Object cacheKey = getCacheKey(bean.getClass(), beanName);     // 这里在按照正常流程创建AOP代理对象时会判断缓存earlyProxyReferences中是否有(提前创建代理);防止重复创建代理对象       this.earlyProxyReferences.put(cacheKey, bean);     return wrapIfNecessary(bean, beanName, cacheKey);   }     }
  通过getEarlyBeanReference方法提前创建代理对象。这样就解决了循环依赖时AOP代理问题。保证获取的都是同一个对象。
  其实引入三级缓存还解决了一个问题就是延迟代理对象的创建,如果不应用ObjectFactory方式那么我们需要不管需不需要都要先创建代理对象,而引入ObjectFactory可以在注入的时候先暴露的是ObjectFactory只有在调用getObject方法的时候才去创建真正的代理对象(避免了所有Bean都强制创建代理对象)。当没有被代理时可以直接返回原始对象,如果被代理会提前创建代理对象。
  不用二级直接是用一,三级缓存?
  假设场景:A 依赖 B,B 依赖 A、C,C 依赖 A
  如果这样会出现不同的代理对象,每次调用getObject都会创建不同的代理对象(在上面的场景中如果只用一,三级缓存那么 B 依赖 A会通过getObject获取一个代理对象Proxy$1,接着注入C的时候 C中又依赖A,那这时候又从getObject获取对象那么返回的将又会是一个新的代理对象Proxy$2;在这个过程中A对象就出现了2个不一样的对象了,这肯定是错误的)。而引入二级缓存也就解决了这个问题。只有二级缓存没有的时候才从三级缓存汇总获取(如果需要则创建代理对象,然后保存到二级缓存中,二级缓存中已经是提前创建了代理对象(如果需要代理))。
  当一个Bean完全的创建完以后放入一级缓存中,此时会吧二级三级中的缓存清除。 1.4 关闭循环依赖@Component public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {   @Override   public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {     if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {       AbstractAutowireCapableBeanFactory bf = (AbstractAutowireCapableBeanFactory) beanFactory ;       // 关闭循环依赖         bf.setAllowCircularReferences(false) ;     }   } }
  完毕!!!!
  求个关注+转发
  SpringMVC参数统一验证方法
  SpringBoot多数据源配置详解
  SpringCloud Nacos 整合feign
  Spring AOP动态代理失效的解决方法@Transactional为何会失效
  SpringBoot配置文件你了解多少?
  SpringBoot邮件发送示例 Springboot面试题整理附答案
  SpringBoot项目查看线上日志
  在Spring Cloud 中你还在使用Ribbon快来试试Load-Balancer
  SpringBoot分库分表sharding-sphere3

这样泡脚伤阴,不要再做了俗话说树枯根先竭,人老脚先衰。中医认为,我们的足三阴经和足三阳经分别起始和终止于脚部,它们与手三阴手三阳经共同维持着人体气血运行,是精气之根。现代医学也认为,脚对人体的血液循环起着每天学习一味中药麦芽今天聊聊麦芽,也是很好且常用的消食药,禾本科植物大麦的成熟果实经过发芽干燥而成。麦芽在全国各地均有分布生产,将大麦洗干净,浸泡四至六小时,捞出后保持适宜的温度与湿度,等待其发芽,待前胸后背长痘,痤疮or毛囊炎?医生给出几大防治绝招,简单好用毛囊炎是皮肤科室中最为常见的皮肤疾病之一,是由细菌真菌病毒感染或毛囊损伤为主要发病原因的化脓性炎症疾病。毛囊炎长啥样?细菌性毛囊炎初起为与毛囊口一致的红色充实性丘疹或由毛囊性脓疱疮玻璃女神赵蕊蕊曾与姚明闹出绯闻,40岁仍未婚只因不将就18岁首次为国出战便帮助球队拿到亚锦赛冠军,出道即巅峰却长期饱受伤病困扰,退役后转型当起作家,她就是被称为玻璃美人的前女排主力副攻赵蕊蕊。赵蕊蕊出生于1981年10月,不久前刚度过中国最大沙漠藏有地下海洋,为何不去采?有什么难言之隐?中国最大沙漠发现地下海洋,淡水远超世界20为何迟迟不去开采?你敢想象吗?中国最大的沙漠塔克拉玛干沙漠下面竟隐藏着一片地下海洋,这是一片毫无生命体征的死亡之海。这里平均降水量不足10行星是如何形成的?一颗突然闯入太阳系的流浪太空岩石揭开谜底2017年,一块形状奇特轨道异常不稳定的岩石席卷了太阳系,它一到就离开。天文学家很快意识到它不是来自这里的。它从上到下穿过行星的轨道平面,就像向飞镖盘的同心环投掷的飞镖一样,它移动沙漠植被基因金矿值得挖掘智利研究团队在智利北部的阿塔卡马沙漠建立了一个无与伦比的天然实验室,这里是地球上最干燥最恶劣的环境之一。图片来源美国国家科学院院刊一个国际科研小组研究了能在地球上最恶劣环境之一智利科学家开发新技术有望制造出牢不可破的复合玻璃屏幕由于昆士兰大学进行的突破性研究,手机屏幕破裂可能成为过去的事情。由昆士兰大学的侯京伟博士王连洲教授和陈薇琪教授领导的全球研究团队,已经开发了生产下一代复合玻璃的技术,用于照明LED撒哈拉沙漠有多深,如果挖空沙子,下面还能剩下什么?综述在我们的中学学习中,经常会出现这样一个有意思的现象,就是往往那些最特别的事物最能引起我们的兴趣,也最令我们印象深刻,比如各种世界之最。世界上最高的山峰,珠穆朗姆峰,世界上最长的沙漠之下有很多石油,但为什么我国不愿开采?看完佩服中国的智慧综述18世纪以来,英国传统的工厂手工业逐渐无法满足广大的市场需要,珍妮纺织机被生产了出来,代表了工业革命的序章,这时机器其实并没有受到广泛的应用。直到瓦特将蒸汽机进行了改良,英国原吉林大学发现距今约9000年的古老遗传谱系中国青年报客户端讯(中青报中青网记者王培莲)近日,由吉林大学牵头的中外研究团队发布最新研究成果借助最新的古基因组技术,研究人员发现新疆塔里木盆地的古老人群代表了一支距今约9000年
劳动力紧缺?催生无果,全面放开生育,人们会多要孩子吗?随着时代的发展,人们在很多方面的观念都发生了改变。就拿消费这件事情来说,以前很多人都不舍得花钱,有一点钱就赶紧存起来。但现在,很多年轻人不仅不存钱,反而还超前消费。事实上,除了消费31!爆冷!掀翻夺冠大热门,带刀后卫双响,角球直接爆射入网中国女足留洋球员大放异彩,让中国女足的球迷们仿佛过节一样兴奋不已。李梦雯用自己的霸气,用自己的速度,用自己的技术,用自己的拼劲,打通了大巴黎女足的右路进攻通道,让大巴黎得势不得分的今日复合肥磷铵钾肥出厂价格9月21日哈喽,大家好!这里是化肥价格行情!关注我每天看最新化肥价格行情!今天(9月21日)今日国内复合肥市场整体趋稳运行,一铵小幅反弹钾肥价格下调50100元吨。下面我们看看具体价格行情!虎年生了个女儿,那就给她起个有见识有气度的名字吧头条创作挑战赛女孩子,一般都是很文静的,人们起名字也喜欢安静温馨的,但是今天小暖来给大家推荐有着大女主范的女孩名,活泼开朗坚韧不拔,有见识有气度!小暖觉得虎年出生的女孩子,起个这样产后知识生完孩子当天吃什么?分娩是一项严重损耗体力的活动,因此产妇急需能量来补充营养。但产妇却又不能马上吃蛋鱼肉等营养价值高的食物,因为她的肠胃功能还很弱,尤其是剖腹产产妇,只能吃一些易消化的食物。这时候家人沁园春国庆73周年张德敏(三河)阳光万里,山河壮丽,红旗高扬。望神州上下,举杯同庆,华夏浩荡,九州流芳。和谐稳定,人民幸福,时代乐曲奏华章。新中国,如睡狮猛醒,屹立东方。今朝如此辉煌,赖特色思想指方又一男星宠妻人设崩塌!三个人的合照,有马蓉宋喆那味儿了叒有明星翻车了!最近有网友自曝被一家影视培训学校骗钱学费十万,退学不退钱。以及骗身未遂学校拉皮条,怂恿学员陪酒献身导演。其实它四年前就被曝过只教无实物表演学生剧组两头赚钱退学得先招抄袭大王郭敬明,终于为自己的傲慢付出了代价文2号探秘人编辑2号探秘人小学2年级时,就挣到了人生第一笔稿费。上中学后,就登上了全国公开刊物,并通过第三届新概念作文初赛。刚刚18岁,就拿到了新概念作文大赛一等奖。在他未成年的那9月LPR按兵不动,如何影响恢复中的楼市?北京日报客户端记者曹政9月20日,中国人民银行授权全国银行间同业拆借中心公布,1年期LPR为3。65,5年期以上LPR为4。3,与前值保持一致。同时,贝壳研究院披露的重点城市主流房学习手记追随内心的直觉破除小我的执念(一)人生就是一个选择的过程。在做选择的过程中,最好的情况是在觉知的状态中,可以调动感性(Followmyheart)和理性的力量(Followmymind),做出合理的选择。Follo一个人爱你入骨后,会有明显的转变,假装不了文丨桃小菁春风十里不如你,小菁在这里,等着你!如果要给爱分等级,那最高的一个等级,非深入骨髓的爱莫属。该是何等的深情,才能融入到骨血里?该是何等的幸运,才能收获这样的爱情?男女之间姚明现身悉尼肚腩抢镜,体重疑超400斤,被曝已移民澳洲真假难辨饿了吗?戳右边关注我们,每天给您送上最新出炉的娱乐硬核大餐!9月21日,多位网友晒出在悉尼偶遇姚明的视频。他独自一人乘坐飞机出国,在人群中总是低着头往前走,十分低调,但如此瞩目的身特纳阿尔特塔对球员要求很严格,在他治下我进步了很多近日,阿森纳门将马特特纳在接受采访时谈到了他加盟球队后与阿尔特塔的相处,并透露阿尔特塔在球场上是一个非常有激情的人。特纳表示当时我们开展的一次控球训练,以比赛的方式进行,当时我非常美国在加息,中国却在降息,这背后的博弈谁能赢?北京时间9月22日,美联储将发布议息决议,市场预计此次加息幅度将达到75个基点以上。如果美联储的议息决议符合预期,这将是美联储今年以来的第5次加息,也将是首次连续在三次会议上加息7九球女神车侑蓝曾和潘晓婷齐名,依旧美艳,嫁给大14岁丈夫体育明星一向拥有很高的人气,如果是美女,那就更容易吸粉了。以中国体坛为例,张常宁潘晓婷刘湘等美女,都是实力和颜值兼具的女神,拥有很多的粉丝。潘晓婷被誉为九球天后,巅峰时期球技非常出C罗又获大奖!颁奖礼上宣布世界杯后不退队,39岁还要踢欧洲杯北京时间9月21日,葡萄牙足协举办了第四届金盾奖颁奖典礼。C罗穆里尼奥葡萄牙五人制足球队等获奖。而C罗也盛装出席,并领取了国家队最佳射手奖。C罗还在颁奖礼上霸气宣布,世界杯后自己不封神一战!张帅挽救赛点大逆转,爆冷淘汰世界第10,对手愤怒砸球WTA500东京站,33岁中国金花张帅封神,在先输一盘,此后一度面临赛点的情况下,张帅大逆转,淘汰赛会2号种子世界排名第10的加西亚,爆出大冷门!加西亚全场发出27记Ace,但没能女篮世界杯首战,韩国队名单出炉,中国队身高占优,杨力维成队长女篮世界杯将于9月22日开启,中国队将迎来小组赛首战对手韩国队,具体时间是下午15点30分,双方大名单分别如下中国队中锋李月汝(99年200厘米)韩旭(99年208厘米)迪拉娜(9目瞪口呆!普利西奇在新书中对前主教练图赫尔发出嘲讽10月18日,克里斯蒂安普利西奇的书,我迄今为止的旅程将发行。这本书将讲述他从宾夕法尼亚州时的一名足球运动员,到目前在切尔西担任的角色,并带领美国男子国家队前往世界杯。但在书中,他iOS16获史诗级更新主动粘贴不再弹窗中关村在线消息苹果近日向开发人员发布了iOS16。1Beta2版本,该测试版是在第一个iOS16。1测试版发布一周后发布的。开发者可以从Apple开发者中心下载iOS16??和iPIOS15。7,老机型的福音呀今天无意中看到一位博主将手里的备用机苹果6splus更新到15。7,在续航能力运行流畅度发热三个方面进行了测试,相比于14。6,居然均有一些提升。我手里也有一部用作备用机的苹果6SiQOONeo6SE对比RedmiK40S手机对比Neo6SE对比K40SiQOONeo6SE更大的电池容量更快的有线充电屏幕指纹识别更轻的重量RedmiK40S更好的盖板更快的内存规格更好的前置相机侧面指纹识别更多的5G