Spring源码:Bean生命周期(终章)

前言

本系列前面讲解了Spring的bean定义、bean实例化、bean初始化等生命周期。这些步骤使我们能够了解bean从创建到准备好使用所经历的过程。但是,除了这些步骤,bean的销毁也是非常重要的一步。在本系列的最后,我们将深入探讨bean的销毁过程,包括在什么情况下会发生销毁、销毁的顺序以及如何在bean销毁之前执行一些清理任务等。通过学习bean的销毁过程,我们将更全面地了解Spring的bean生命周期。

在Spring中,有多种方式可以销毁bean。其中一种方式是在应用程序关闭时显式地调用applicationContext.close()方法来关闭容器。这个方法将会销毁所有还没有被销毁的bean。

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

applicationContext.close();

实现DisposableBean接口

实现DisposableBean接口是一种销毁bean的简单方式。当bean容器关闭时,Spring会调用DisposableBean的destroy()方法来销毁bean。以下是一些示例代码:

import org.springframework.beans.factory.DisposableBean;
@Component
public class MyBean implements DisposableBean {

    @Override
    public void destroy() throws Exception {
        // 在这里清理资源
    }
}

使用@PreDestroy注解

使用@PreDestroy注解是另一种简单的方式来销毁bean。当bean容器关闭时,Spring会调用使用@PreDestroy注解的方法来销毁bean。以下是一些示例代码:

import javax.annotation.PreDestroy;
@Component
public class MyBean {

    @PreDestroy
    public void cleanUp() throws Exception {
        // 在这里清理资源
    }
}

registerDisposableBeanIfNecessary

registerDisposableBeanIfNecessary()方法是一个非常重要的方法,它是在bean创建后进行处理bean销毁逻辑的前提。在Spring的AbstractBeanFactory类中,该方法会检查当前bean是否实现了DisposableBean接口或者@PreDestroy注解,如果是的话,就会将该bean添加到一个DisposableBeanAdapter对象中,该对象会在bean销毁时被调用以执行销毁任务。这个过程是在bean销毁之前执行的,以确保正确关闭应用程序。

    protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
        AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
        if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
            if (mbd.isSingleton()) {
                // Register a DisposableBean implementation that performs all destruction
                // work for the given bean: DestructionAwareBeanPostProcessors,
                // DisposableBean interface, custom destroy method.
                registerDisposableBean(beanName, new DisposableBeanAdapter(
                        bean, beanName, mbd, getBeanPostProcessorCache().destructionAware, acc));
            }
            else {
                // A bean with a custom scope...
                Scope scope = this.scopes.get(mbd.getScope());
                if (scope == null) {
                    throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
                }
                scope.registerDestructionCallback(beanName, new DisposableBeanAdapter(
                        bean, beanName, mbd, getBeanPostProcessorCache().destructionAware, acc));
            }
        }
    }

我大概讲下这个方法requiresDestruction

    protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {
        return (bean.getClass() != NullBean.class && (DisposableBeanAdapter.hasDestroyMethod(bean, mbd) ||
                (hasDestructionAwareBeanPostProcessors() && DisposableBeanAdapter.hasApplicableProcessors(
                        bean, getBeanPostProcessorCache().destructionAware))));
    }
  1. DisposableBeanAdapter.hasDestroyMethod:校验是否实现了DisposableBean或者AutoCloseable接口,如果没有的话,再查看是否bean定义的destroyMethodName属性是(inferred),如果是的话,那么直接找这个类是否有close方法没有的话再找shutdown方法
  2. DisposableBeanAdapter.hasApplicableProcessors:是否有@PreDestroy注解

DisposableBeanAdapter

DisposableBeanAdapter对象是一个适配器,用于在销毁bean时执行必要的处理。它会将DisposableBean接口或@PreDestroy注解的方法转换为一个回调方法,以便在bean销毁时执行。这种适配器模式允许非标准的bean销毁方法与Spring框架协同工作。

在将DisposableBeanAdapter对象添加到一个DisposableBeanRegistry对象中时,Spring会将该对象添加到一个bean销毁的注册表中。当需要销毁所有bean时,Spring就会从该注册表中获取所有需要销毁的bean,并按照正确的顺序执行销毁任务。这样就可以确保应用程序的正确关闭。

destroySingleton

当Spring程序关闭时,会调用destroyBeans方法,这里我们分析关键部分代码:

    public void destroySingleton(String beanName) {
        // Remove a registered singleton of the given name, if any.
        // 先从单例池中移除掉
        removeSingleton(beanName);

        // Destroy the corresponding DisposableBean instance.
        DisposableBean disposableBean;
        synchronized (this.disposableBeans) {
            disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);
        }
        destroyBean(beanName, disposableBean);
    }
  1. removeSingleton:先从单例池中移除掉
  2. this.disposableBeans.remove:这里返回的是我们之前调用registerDisposableBeanIfNecessary方法添加进去的DisposableBeanAdapter适配器
  3. destroyBean:直接销毁bean,这里注意一个小点就是如果当前bean被其他bean依赖了,那么先移除销毁其他Bean,然后就是调用适配器的destroy方法

总结

非常感谢您对 Spring 生命周期系列文章的关注和支持,我们在过去一个月中深入了解了 Spring 框架中 Bean 的生成、初始化、后置处理和销毁等过程,对于理解 Spring 框架的原理和机制非常有帮助。我们总结一下Spring到底做了那些事情将bean从生成到销毁的全过程:

  1. 项目启动时,ClassPathBeanDefinitionScanner扫描得到所有BeanDefinition,由于ACM技术所以此时beanclass属性为String类型的bean的名称
  2. 获取合并后的BeanDefinition
  3. beanClass开始真正的被加载替换原有String类型的bean的名称
  4. 调用实例化前处理方法applyBeanPostProcessorsBeforeInstantiation
  5. 通过构造方法创建Bean实例
  6. 后置处理合并后的BeanDefinition,调用postProcessMergedBeanDefinition(寻找注入点)
  7. 调用实例化后处理方法postProcessAfterInstantiation
  8. 开始进行属性注入:postProcessProperties
  9. 调用初始化前处理方法:applyBeanPostProcessorsBeforeInitialization
  10. 进行初始化:invokeInitMethods,会调用指定init方法或者afterPropertiesSet方法
  11. 调用初始化后处理方法:applyBeanPostProcessorsAfterInitialization(AOP)
  12. 容器关闭时,走bean的销毁逻辑,即今天所讲

这里面有很多逻辑流程我都在单独的文章中有细讲,比如FactoryBean、PropertyValues等等,由于是总结所以就不全写出来了,也希望大家可以好好理解Spring源码,下一步,我们将会着重讲解 Bean 的属性依赖注入。

公众号 ps:以上内容,纯属个人见解,有任何问题下方评论!关注博主公众号,源码专题、面试精选、AI最新扩展等你来看!原创编写不易,转载请说明出处!
本文转载于网络 如有侵权请联系删除

相关文章

  • hadoop集群搭建

    前置工作1.创建虚拟机2.配置虚拟机网络3.WIN10IP地址配置4.CentOS静态IP设置5.克隆三台虚拟机6.jdk安装7.hadoop安装8.SSH免密登录配置(shell脚本单独提供)集群搭建1.集群部署规划192.168.5.102hadoop102192.168.5.103hadoop103192.168.5.104hadoop104集群规划2.配置文件说明及配置事项总共涉及的配置文件有4个:core-site.xml、hdfs-site.xml、yarn-site.xml、mapred-site.xml 存放路径:$HADOOP_HOME/etc/hadoop (1)核心配置文件配置core-site.xmlvimcore-site.xml<?xmlversion="1.0"encoding="UTF-8"?> <?xml-stylesheettype="text/xsl"href="configuration.xsl"?> <configuration>

  • 聊一聊测试中常见的面试题(二)

    接着上次分享的面试题一。今天,我们来聊聊其他面试题。 1.如何测试一个纸杯?功能度:用水杯装水看漏不漏;水能不能被喝到安全性:杯子有没有毒或细菌可靠性:杯子从不同高度落下的损坏程度可移植性:杯子在不同的地方、温度等环境下是否都可以正常使用兼容性:杯子是否能够容纳果汁、白水、酒精、汽油等易用性:杯子是否烫手、是否有防滑措施、是否方便饮用用户文档:使用手册是否对杯子的用法、限制、使用条件等有详细描述疲劳测试:将杯子盛上水放24小时检查泄漏时间和情况;盛上汽油放24小时检查泄漏时间和情况等这里我只是举个例子,还会问登录,加入购物车等功能,这些都会结合你的业务实际,或者是面试公司业务的来问,随机性比较大,但是要注意考虑面。2.软件测试分为几个阶段各阶段的测试策略和要求是什么? 和开发过程相对应,测试过程会依次经历单元测试、集成测试、系统测试、验收测试四个主要阶段:单元测试:单元测试是针对软件设计的最小单位––程序模块甚至代码段进行正确性检验的测试工作,通常由开发人员进行。 集成测试:集成测试是将模块按照设计要求组装起来进行测试,主要目的是发现与接口有关的问题。由于在产品提交到测试部门前,产品开

  • 为什么我们不发展汉化的编程语言?

    从事嵌入式的软件开发十几年,个人的一种感觉是稍微有点英语水平的人就能从事软件开发,但是要达到高手的水准英语还是不可或缺的,其实在编程过程中英语更多是表现在翻阅国外原汁原味的文档,英文不过关的情况下很难看明白,至于在编程的过程中的英文关键字影响其实很小,无论是英文还是中文关键字用的次数多了也就记住了,从理论上讲不懂英文的人也是可以从事编程代码的学习,但是要成为真正意义上的高手还是显得吃力一些,要比通常意义上的程序员要费劲而且在概率上也会小一些,毕竟如果英文不达标可能就是学历层面的问题,影响的不仅仅是英文可能还会有数学基础。为什么中国的汉化编程语言进展的如此缓慢?汉化编程语言本身的意义不是很大。如果单纯从替换关键字的概念入手来解决问题,只是在外观上显得好理解一些,在真正写代码的时候思维逻辑方式还是一样的,而且目前计算机的架构就是基于冯诺依曼在机器码里面就是一堆的0和1的组合方式,而且设计者本身是基于英文体系,所以转化成中文在效率也会打折扣,同样是能够编程没有必要非要转化成中文去编程。首先要搞清楚一点编程的关键是编程逻辑,就是设计上的逻辑层次,至于具体代码的编写可能在初级阶段觉得特别的难,磨

  • 浅谈设计模式(二):装饰器模式|中介模式|原型模式

    装饰器模式(DecoratorPattern)装饰器模式可用来给一个类动态添加功能,将其装饰成一个新的类。这就是装饰器的概念。看到这里我们可能会想,要达到这种效果,我们用子类继承父类不就可以了吗?没错装饰器模式,本身是一种继承的替代方案。那既然是替代方案,那么自然就有它不一样的地方。具体区别在哪里呢?请看装饰器模式更灵活:继承时父子类的关系是静态的,而装饰器模式是动态的,装饰类和被装饰类的关系是运行时候确认的装饰类和被装饰类的耦合关系是松散的,各自可以独立变化下面看看具体的代码。具体过程可看注释//1.首先我们有一个Pen接口 publicinterfacePen{ publicvoidwrite(); } //2.Pencil类实现了Pen这个接口 publicclassPencilimplementsPen{ publicvoidwrite(){ System.out.print("写"); } } //3.装饰类PencilDecorator也实现了Pen这个接口,且代理调用Pencil的方法 publicclassPencilDecoratorimpleme

  • 37篇!Facebook今年被CVPR收录的论文都说了啥?

    AI科技评论按:CVPR2019已于6月16日至20日在美国加利福利亚州长滩市盛大举办,吸引了超过万人参加,雷锋网AI科技评论的记者也前往现场为大家带来了精彩的大会报道。作为工业界的学术实力干将之一,FacebookAI研究院在本次大会上的成果也备受瞩目。而FacebookAI研究院也对自己今年的战绩进行了统计:共有37篇论文被收录,其中包括15篇Oral论文。下面就让我们一起来看看这些成果吧。Oral论文一览《2.5D视觉声音》2.5DVisualSound作者:RuohanGao,KristenGrauman双声道音频为听者提供了3D的听觉感受,让人对场景有丰富的感知体验。然而,双声道录音几乎是不可实现的,即使能实现也需要相当水平的专业知识和设备。我们建议利用视频将普通的单声道音频转换成双声道音频,其关键思想是,视觉帧揭示了重要的空间线索:尽管单声道音频在完成过程中明显缺乏这些空间线索,但它们与空间线索紧密相连。我们的多模态方法可以从未经标注的视频中还原空间线索与单声道音频的这一联系。我们设计了一个深卷积神经网络,通过注入有关目标和场景配置的视觉信息,将单声道(单通道)原声解码成对

  • 独家 | 谷歌发布NLP最先进预训练模型:开源BERT

    作者:JacobDevlinandMing-WeiChang,ResearchScientists,GoogleAILanguage 翻译:佟海宁校对:吴金笛本文约2000字,建议阅读9分钟。本文为你介绍谷歌最新发布的自然语言预训练模型BERT。简介自然语言处理(NLP)面临的众多挑战之一是训练数据的短缺。由于NLP是一个具有许多不同任务的多样化领域,因此大多数针对特定任务的数据集仅包含了几千到几十万个人为标记的训练示例。然而,现代基于深度学习的NLP模型往往需要更大量的数据,在拥有在数以百万计甚至十亿计的带标注的训练样例上进行训练时性能将会得到极大改善。为了帮助缩小数据差距,研究人员开发了各种技术用于使用网络上海量未标注的文本(称为预训练)来训练通用语言表示模型。然后,将其应用于小数据NLP任务(如问答和情感分析)微调预训练模型,与从头对数据集进行训练相比,使用预训练模型可以显著地提高准确度。本周,我们公布了一项用于NLP预训练的新技术,称为双向编码器表示的变形器(BidirectionalEncoderRepresentationsTransformers),即BERT。通过这个模

  • 手把手教妹子用WordPress建一个公司官网(2):神器Elementor

    书接上回,上篇文章里介绍了域名和WordPress托管服务这些前置步骤,相当于一个公司官网的基础设施建设,房子已经盖起来了,本篇我们来继续搞一下装修。看看怎么快速把一个毛坯房改造成高大上的“民宿”PageBuilder是什么?首先,介绍一个概念:PageBuilder—可视化编辑器,也可以叫页面构建器。PageBuilder是一种WordPress插件,可以把WordPress上的页面、文章的内容编辑区变成模块化的可拖拽区,创建、编辑、自定义各种操作完全是图形化、可视化操作,所见即所得,让用户可以在浏览器中搭建出美观又专业的页面布局。如果这样说还是比较抽象的话,可以把PageBuilder比喻成这样一种东西,它是一种可以把记事本变成PowerPoint的神器存在,通过鼠标拖拖拽拽点点按按就能作出高大上的PPT。国外有很多非常强大的PageBuilder,Elementor也是其中的佼佼者。下面是几个有代表性的WordPressPageBuilder:ElementorBeaverBuilderDiviVisualComposerWebsiteBuilderThemifyBuilderP

  • cuDNN和NCCL

    在Training方面比较重要的库是cuDNN。cuDNN是深度学习基础模块加速库,可以支持所有主流的深度学习框架,比如Caffe、Tensorflow、CNTK、Theano、PyTorch等,这些基础模块指的是深度学习框架中常用的一些layer(神经网络层)操作,比如卷积、LSTM、全连接、Pooling(池化层)等。那么cuDNN的优势有什么呢?首先它将layer专门针对GPU进行了性能调优;第二是cuDNN以调用库函数的方式进行神经网络设计,能够大大节省开发者的时间,让大家可以将时间和精力集中在神经网络的设计和实现,而不是去进行GPU代码的开发和性能调优。在这个benchmark中大家都可以看到,分别使用了八颗不同架构的GPU服务器对GoogLeNet网络进行训练的性能对比,大家可以只看最后两个绿色的柱状图,分别代表的是八颗P100的DGX-1服务器以及八颗TeslaV100的DGX-1V服务器。大家可以看到二者的性能差异大概是在2.5倍左右,也就是我们在TeslaV100上进行DeepLearning训练时的性能提升水平。接下来介绍的SDK是NCCL。深度学习中常常需要多GP

  • 【Google 年度顶级论文】机器学习系统,隐藏多少技术债?

    原文在此:google原文 1.介绍随着机器学习(ML)社群持续积累了几年对于活跃系统(livesystems)的经验,一种让人不舒服的趋势广泛地浮出水面:研发和部署机器学习系统相对来说是既快速又便宜的,但维护它们却很困难,并且成本昂贵。 这种对立可以用“技术债”的框架来理解。1992年WardCunningham引入了这个比喻,用来帮助解释在软件工程领域里因为进展快速而带来的长期成本。就像欠下财政债务一样,欠下技术债务也总是有充分的战略性原因。并不是所有的债务都是不好的,但是,所有的债务都需要付出利息。技术债可能通过:重构代码(refactoringcode)、改进单元测试(improvingunittests)、删除无用代码(deletingdeadcode)、降低依赖(reducingdependencies)、精简应用程序接口(tighteningAPIs)、以及改进说明(improvingdocumentation)的方式来逐渐偿还。这些行动的目标并不是为了增加全新的功能,而是为了使未来能够继续改进,减少报错,以及提高维护性。推迟偿还只会带来越来越高昂的成本。因为技术债会高速

  • 弃用 Windows,政府机构 5000 万台电脑将替换为国产 Linux!

    点击关注公众号,Java干货及时送达来源:https://www.linuxmi.com/50-million-pc-linux.html开源社区的一大胜利!继德国之后,中国现在想在5000万台PC上抛弃Windows并运行Linux!如果您一直密切关注Linux新闻,您可能听说过德国去年在超过25000台PC上放弃Windows转而使用Linux。那时,社区预测许多其他国家可能会放弃Windows转而使用Linux。中国最近宣布将在超过5000万台PC上放弃Windows转而使用Linux,这一预测可以说是非常准确!虽然两国的最终目标相同,但他们这样做的理由却不同。德国这样做是为了让政府可以节省许可成本并促进开源。中国这样做是为了“删除外国操作系统”,以便他们可以在国内维护操作系统。虽然这对于Linux和开源软件来说是一个巨大的胜利,但对于戴尔、惠普等笔记本电脑/PC制造商以及Adobe和微软等软件公司(联想和金山除外)来说却是个坏消息。虽然制造商将被迫成为“外国”公司,但联想、华为和金山等本土公司可能会在未来几年看到快速的市场增长。以下是彭博所说的。据彭博社报道,如果政府机构和公司

  • 腾讯云SSL证书域名型(DV)免费SSL证书申请流程

    注册帐号腾讯云平台申请证书首先需要注册腾讯云账号并且完成实名认证。1.新用户请单击腾讯云官网右上角的免费注册,进入注册页面。2.请您注册腾讯云账号,即可登录腾讯云控制台。3.完成实名认证,方可继续申请证书。n申请免费证书说明免费证书仅提供二级域名及其子域名证书申请,不支持IP与泛域名申请。例如dnspod.cn、docs.dnspod.cn。亚洲诚信范围内(不一定在腾讯云申请)的同一主域最多只能申请20张免费证书,申请时请注意该域名是否在其他服务商平台存在亚洲诚信下的证书,避免申请达到上限无法申请。更多详情可参考免费证书名额相关问题。免费证书到期后如需继续使用证书,请重新申请并安装。1.登录SSL证书管理控制台,进入“我的证书”管理页面,并单击申请免费证书。如下图所示:n2.在弹出的确认证书类型窗口中,单击确定。如下图所示:n3.填写证书申请内容,例如qcloud.com,cloud.tencent.com,demo.test.qlcoud.com,并单击下一步。如下图所示:n算法选择:勾选所需证书的加密算法。加密算法具体内容可查看RSA加密算法与ECC加密算法的区别?

  • shell脚本编程基础

    Shell脚本编程基础 本部分内容: 11.2创建shell脚本文件 在创建shell脚本文件时。必须在文件的第一行指定要使用的shell。其格式为:#!/bin/bash复制在通常的shell脚本中,#用作注释行,shell并不会处理shell脚本中的注释行,然而,shell脚本文件的第一行是个例外,#后面的感叹号会告诉shell用哪个shell来运行脚本(是的,你可以使用bashshell,同时还可以使用另一个shell来运行你的脚本) 在指定了shell之后,就可以在文件的每一行中输入命令,然后加一个回车符,之前提到过。注释可用#添加,例如:$vimtest1 #!/bin/bash #Thisscriptdisplaysthedateandwho’sloggedon date who复制这就是脚本的所有内容,但是在运行新的脚本之前,还要做一些其他的事情,现在运行脚本,结果可能会叫你有点失望。 因为在创建文件的时候,umask的值决定了新文件的默认权限设置,所以系统创建的文件只有文件只有文件属主和属组才有度/写权限 通过chmod命令赋予文件属主执行文件的权限。chmod+xte

  • 函数调用的arm汇编实现

    看《ARMSystemDeveloper'sGuide:DesigningandOptimizingSystemSoftware》中5.5节functioncall,讲的不是很具体 发现网上的这份资料讲解非常好,以arm64为target,言简意赅,下面是目录 (1)CallingandreturningHowdoescallerfunctionjumptocalleefunction?Howdoescalleefunctionjumpbacktotherightplaceincallerfunction? (2)PassingargumentsHowdoescallerfunctionpassargumentstocalleefunction? 注释:这里没有讲到多个参数传递(参数个数大于某个数量,因为arm传参标准规定,只能用寄存器的几个作为参数传递,参数再多,就需要用另外的机制了) 和结构体传递(将多个相关的参数封装成结构体,然后传结构体的地址,从而就可以不使用前面说的多个参数传递行为) (3)StoringlocalvariablesWheredoescalleefunctio

  • 使用Nuget对类库进行打包

    使用Nuget对类库进行打包,并将类库上传到nuget上面。   步骤 1、在nuget官网注册账号,并登陆。 https://www.nuget.org 2、下载Nuget.exe,并将其本地路径加入环境变量中。   这样你可以不用来回的copynuget.exe文件了,在任何地方都可以使用nuget命令。 3、生成打包appKey   4、发布前需要对包的一些属性进行设置,当然你可以通过vs自带的功能进行设置   可以勾选生成nuget包。或者使用命令的方式。 使用cmd命令进入类库项目文件所在的目录   成功之后,可以在该目录发现多了一个Suny.Infrastructure.1.0.0-pre1.nupkg的文件,这个文件就是nuget发布的包文件。 或者通过vs进行发布类库的方式发布nuget包、 6、发布包 最简单的方式是通过nuget服务上传包即可,也可以通过命令的方式push。   总结 在进行实际操作的时候,发现命令push的时候总失败,这里先用上传包的方式,命令行的方式,之后进行补充。通过nuget管理

  • 微信支付V3版本的Python使用方法

    微信支付自推出V3版本接口以来,体验下来确实比V2有了很大的提升,但介于其官方没有提供Python版本的SDK,故在此记录通过Python3来使用微信支付V3的主要过程。 1.搞清楚自己的身份 这一步看似可以忽略,但也需要仔细,笔者之前就犯了一个错,看了不对应的文档。微信支付的商家有两种身份模式:普通商户、服务商。 一般的大部分商户都是属于普通商户,只有品牌商等才为服务商,并且两者身份不能互换。 普通商户的API文档:https://pay.weixin.qq.com/wiki/doc/apiv3/index.shtml 服务商API文档:https://pay.weixin.qq.com/wiki/   2.配置阶段 需要在商户端界面申请API证书和配置APIv3密钥,次过程可以参考每一个步骤右侧的查看指引按钮。           3.构造签名 V3版本的接口调用需要对请求进行签名,参考https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatp

  • MIM软件介绍

    MIM是一款通过手机网络给好友发送语音、文字消息、表情、图片和视频等功能的即时通讯软件。最新版本十分人性化,支持SVG,可以撤回两分钟内发出的最后一条消息,发出去的信息可以收回。   【微信简介】复制 1.可以发语音、文字消息、表情、图片、视频。30M流量可以收发上千条语音,省电省流量。复制 2.朋友圈,跟朋友们分享生活点滴。复制 7.表情商店,有趣好玩的表情在这里。复制   【软件功能】复制 聊天消息:随时随地收发好友和群消息,一触即达。复制 语音通话:两人、多人语音通话,高清畅聊。复制 视频聊天:亲朋好友,想念不如相见。复制 文件传输:手机、电脑多端互传,方便快捷。复制 个性装扮:主题、名片、彩铃、气泡、挂件自由选。复制   【常见问题】复制 1.没有删除的话,你可以直接看到的复制 2.如果你删除了,你可以通过以下方法找到复制  复制 【基本信息】复制 作者:Micro复制 版本:7.0.3复制 系统:Window10以上复制 框架:Framework4.5以上复制 语言:中文复制  复制 【更新日志】复制 界面全新改版,更清晰直观

  • MySQL 学习笔记(一)MySQL 事务的ACID特性

    MySQL事务是什么,它就是一组数据库的操作,是访问数据库的程序单元,事务中可能包含一个或者多个SQL语句。这些SQL语句要么都执行、要么都不执行。我们知道,在MySQL中,有不同的存储引擎,有的存储引擎比如MyISAM是不支持事务的,所以说MySQL事务实际上是发生在存储引擎部分。 事务主要有四大特性,分别是原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。它实际上是从四个方面来阐述MySQL事务的特点,下面就分别来看MySQL通过什么方式来实现这些特性。 一、原子性# 1.原子性定义# 原子性就是指事务的不可分割性,对于一个事务而言,就是要么都执行,要么都不执行。在MySQL中是通过回滚来实现,比如事务中的一个SQL语句失败了,那么该事务的所有SQL语句必须都进行回滚,退回到事务前的状态。 2.InnoDB中原子性的实现# 上面说到,MySQL中原子性是通过回滚的方式来实现,那么回滚是怎么实现的?这就涉及到MySQL中的Undo日志,原子性就是通过Undolog来实现的。 具体是Undolog会在一个事务

  • 校花网爬取

    前言 联系爬虫使用 正文 1、堆糖校花网API: 获取数据的api: https://www.duitang.com/napi/blog/list/by_search/?kw=%E6%A0%A1%E8%8A%B1&start=0&limt=1000复制 图片路径"path": https://b-ssl.duitang.com/uploads/item/201509/18/20150918195615_JfdKm.jpeg复制 2、简要介绍爬虫: (1)从技术层面来说就是通过程序模拟浏览器请求站点的行为,把站点返回的HTML代码/JSON数据/二进制数据(图片、视频)爬到本地,进而提取自己需要的数据,存放起来使用; (2)从解析过程来说: 方式1:浏览器提交请求--->下载网页代码--->解析成页面 方式2:模拟浏览器发送请求(获取网页代码)->提取有用的数据->存放于数据库或文件中 爬虫要做的就是方式2; 爬虫过程图 3、过程各个阶段的主要介绍: (1)发起请求 使用http库向目标站点发起请求,即发送一个Request Reques

  • 数据结构学习笔记(2)——链表创建和链表遍历

    说明(2018-3-1520:34:49): 1.开始将pNew挂到pHead后面,会有问题,每个新生成的节点都挂到了pHead后面。 2.然后改为,新建一个pTail尾节点,让它等于pHead,然后每次生成一个新节点,就让这个pTail等于这个新节点,以便下一个新节点能够挂到这个pTail尾节点上,也就是上一个旧节点。   1#include<stdio.h> 2#include<malloc.h> 3#include<stdlib.h> 4#pragmawarning(disable:4996) 5 6 7typedefstructNode 8{ 9intdata;//数据域 10structNode*pNext;//指针域 11}NODE,*pNODE; 12pNODECreateList(); 13voidTraverseList(pNODEpHead); 14voidmain() 15{ 16pNODEpHead=CreateList();//生成一个链表,把链表中第一个节点的地址赋给pHead 17TraverseList

  • VUE知识点

    vue强制更新$forceUpdate() 添加this.$forceUpdate()进行强制渲染,效果实现。因为数据层次太多,render函数没有自动更新,需手动强制刷新。 调用强制更新方法this.$forceUpdate()会更新视图和数据,触发updated生命周期。 sync修饰符 vue修饰符sync的功能是:当一个子组件改变了一个prop的值时,这个变化也会同步到父组件中所绑定。如果我们不用.sync,我们想做上面的弹窗功能,我们也可以props传初始值,燃后事件监听,实现起来也不算复杂。 v-bind="$attrs" 传送门 https://www.cnblogs.com/jin-zhe/p/13099416.html

  • centos7一步一步搭建docker jenkins 及自定义访问路径重点讲解

      centos7一步一步搭建dockerjenkins及自定义访问路径重点讲解   https://www.cnblogs.com/jying/p/12173090.html

相关推荐

推荐阅读