板块一 Servlet编程:第二节 Servlet的实现与生命周期 来自【汤米尼克的JAVAEE全套教程专栏】

板块一 Servlet编程:第二节 Servlet的实现与生命周期

  • 一、Servlet相关概念
    • Serlvet的本质
  • 二、中Web项目中实现Servlet规范
    • (1)在普通的Java类中继承HttpServlet类
    • (2)重写service方法
      • 编辑项目对外访问路径
  • 二、Servlet工作流程
  • 三、其它实现Servlet规范的方式
    • (1)继承自GenericServlet 类
    • (2)实现Servlet接口
    • (3)在HttpServlet中直接重写doGet()和doPost()方法
  • 四、Servlet生命周期

在上一节的内容中,我们已经系统的学习了HTTP的相关概念、知道了GET和POST请求在服务器上的运行原理、请求响应在服务器中究竟是怎样运行的,从这一节开始我们将系统的学习实现Servlet的完整过程

一、Servlet相关概念

Serlvet的本质

  • 当编写Java程序想要在网上实现聊天、发帖、这样一些的交互功能,普通Java技术是非常复杂的,试想要从底层搭建出一整个服务层的代码有多复杂?并且每个人搭建的底层还不一样,为了解决这个问题,sun公司就提供了Serlvet这种技术供我们使用。Servlet是Server与Applet的缩写,是服务端小程序的意思,本质上就是一个遵循Servlet开发的Java类,由服务器调用,在服务器端运行,它的创建、使用、销毁都由Servlet容器进行管理,其常见容器有很多,如Tomcat,Jetty,WebLogic Server,WebSphere,JBoss等等(在Tomcat的集成这一节中我们已经详尽的学习了Tomcat),更奇怪的是Servlet没有main()方法,本质上我们可以想象Servlet通过某种注入回调方法与Servlet容器取得联系,从而代替我们在Servlet中书写main()函数
    在这里插入图片描述
  • Servlet与HTTP紧密联系,可以处理与HTTP协议相关的所有内容,这是Servlet应用广泛的原因之一
  • 实际上在运行JSP时,服务器底层将JSP编译成一个Java类,这个类就是Servlet,因此可以说JSP就是Servlet(详见JSP追根溯源小节)
  • Servlet在 JAVA WEB项目中的位置,它就是我们常说的后端

在这里插入图片描述

  • 编程学习越往后越是如此,我们能做的其实很有限。大部分工作框架都已经帮我们做了。只
    要我们实现xx接口,它会帮我们创建实例,然后搬运(接口注入)到它合适的位置,然后一套既定
    的流程下来执行到创建我们需要的实例

二、中Web项目中实现Servlet规范

我们已经在板块零的第二节中创建了Java Web项目;又在板块零的第三节中成功把Tomcat集成到IDEA中,现在我们就在这个Web项目中实现Servlet规范

(1)在普通的Java类中继承HttpServlet类

在www.caijiyuan包中创建一个普通的Java类
helloServlet.java
在这里插入图片描述
此类继承HttpServlet类,还记得继承怎么写吗:extends
在这里插入图片描述

(2)重写service方法

在上一节中我们详细学习了请求响应在服务器中究竟是怎样运行的,而在Servlet中请求响应就是通过HttpServlet类中的service方法实现的,service方法有两个形参(Request,Rrsponse)分别对应请求、响应
在HttpServlet类中,IDEA重写方法的快捷键是Ctrl+O在这里插入图片描述
但我们发现有两个service,它们的区别是什么?
先来看第一个,HttpServlet的service()方法

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取http request的method参数,其实就是html的form标签  
        //中method属性对应的字符串 
        String method = req.getMethod();
        long errMsg;
        //判断请求方式
        if(method.equals("GET")) {
            //获取最后被修改时间 
            errMsg = this.getLastModified(req);
            if(errMsg == -1L) {
            /**如果servlet不支持http request header的if-modified-since属性 
             * 则继续处理 
             **/  
                this.doGet(req, resp);
            } else {
               //如果支持这个属性 
                long ifModifiedSince;
                try {
                    ifModifiedSince = req.getDateHeader("If-Modified-Since");
                } catch (IllegalArgumentException var9) {
                    ifModifiedSince = -1L;
                }
               /** 
                * 如果客户端的文件最后修改时间和服务器端的文件最后修改时间一致则返回304不需要修改状态 
                * 这样服务器就不返回html,浏览器读取本地缓存文件,否则重新获取服务器端的对应html文件 
                **/  
                if(ifModifiedSince < errMsg / 1000L * 1000L) {
                    this.maybeSetLastModified(resp, errMsg);
                    this.doGet(req, resp);
                } else {
                    resp.setStatus(304);
                }
            }
        } else if(method.equals("HEAD")) {
            errMsg = this.getLastModified(req);
            this.maybeSetLastModified(resp, errMsg);
            this.doHead(req, resp);
        } else if(method.equals("POST")) {
            this.doPost(req, resp);
        } else if(method.equals("PUT")) {
            this.doPut(req, resp);
        } else if(method.equals("DELETE")) {
            this.doDelete(req, resp);
        } else if(method.equals("OPTIONS")) {
            this.doOptions(req, resp);
        } else if(method.equals("TRACE")) {
            this.doTrace(req, resp);
        } else {
            //如果请求不是以上的所有请求方式,该方法就会响应501错误,也就是不支持这种请求
            String errMsg1 = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[]{method};
            errMsg1 = MessageFormat.format(errMsg1, errArgs);
            resp.sendError(501, errMsg1);
        }
    }

这是第二个ServletRequest

public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        HttpServletRequest request;
        HttpServletResponse response;
        try {
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)res;
        } catch (ClassCastException var6) {
            throw new ServletException("non-HTTP request or response");
        }
        this.service(request, response);
}

原来只有第二个 ServletRequest service方法是由Tomcat自动调用,它将接收的客户端请求转交给HttpServlet中的第一个HttpServletRequest protected service方法,此保护类型的service方法再把将请求分发给doPost()doGet()方法进行下一步处理
因此这里就Request/Response俩个形参而言,重写调用第一个或第二个service方法的效果应该是一样的,此处我们直接重写第一个,也就是 HttpServletRequest protected service
在这里插入图片描述

编辑项目对外访问路径

我们还应将项目对外访问路径(就是在服务器中此项目的站点名)更改为自己想要的样子
在这里插入图片描述此处我更改为与包名一致/www.caijiyuan
在这里插入图片描述

注意:我们还应在类前设置注解@WebServlet("/helloServlet"),告诉服务器当前资源在站点下的真实路径

helloServlet.java中写入测试内容

package www.caijiyuan;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/helloServlet")
public class helloServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        super.service(req, resp);
        //打印内容在控制台
        System.out.println("Hello Servlet with terminal");
        //通过流输出数据到浏览器
        resp.getWriter().write( "Hello Servlet with brower");
    }
}

启动服务器在浏览器中访问得

在这里插入图片描述
在控制台得
在这里插入图片描述

二、Servlet工作流程

那么HttpServletRequest request请求是在服务器中是怎样接受到的呢?
即是上一节中详解过的请求头的功劳

在这里插入图片描述
当请求进入服务器时

  1. 服务器会通过请求头键值对中的Host中的localhost找到主机本机
  2. 通过8080端口确定本机中占用端口的程序Tomcat
  3. 通过请求行中的"/www.caijiyuan"确定是Tomcat下的哪个站点
  4. 通过"/helloServlet"确定是当前站点下的那个资源路径

找到资源路径后,如果服务器是第一次被访问就会创建一个Servlet否则就会调用service方法生成request对象来处理会话中的请求;接受到请求后经过设定的代码生成response对象保存响应内容返回给客户端(浏览器),这就是Servlet工作的流程

三、其它实现Servlet规范的方式

(1)继承自GenericServlet 类

对于一个 Servlet 类,我们日常最常用的方法是继承自 HttpServlet 类,实际上,HttpServlet是扩展了GenericServlet 类。GenericServlet 类实现了Servlet,ServletConfig和Serializable接口。它主要完成了这些任务:

  • 将 init() 中的 ServletConfig 赋给一个类级变量,可以由 getServletConfig 获得;
  • 为 Servlet 所有方法提供默认实现的接口(除了service方法);
  • 可以直接调用 ServletConfig 中的方法;
    它的基本结构如下:
abstract class GenericServlet implements Servlet,ServletConfig{
 
   //GenericServlet通过将ServletConfig赋给类级变量
   private trServletConfig servletConfig;
 
   public void init(ServletConfig servletConfig) throws ServletException {

      this.servletConfig=servletConfig;

      /*自定义init()的原因是:如果子类要初始化必须覆盖父类的init() 而使它无效 这样
       this.servletConfig=servletConfig不起作用 这样就会导致空指针异常 这样如果子类要初始化,
       可以直接覆盖不带参数的init()方法 */
      this.init();
   }
   
   //自定义的init()方法,可以由子类覆盖  
   //init()不是生命周期方法
   public void init(){
  
   }
 
   //实现service()空方法,并且声明为抽象方法,强制子类必须实现service()方法 
   public abstract void service(ServletRequest request,ServletResponse response) 
     throws ServletException,java.io.IOException{
   }
 
   //实现空的destroy方法
   public void destroy(){ }
}

可以看到如果继承这个类的话,我们必须重写 service() 方法来对处理请求
继承自GenericServlet 类实现Servlet

package www.caijiyuan;

import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;

@WebServlet("/Servlet_Gener")
public class Servlet_Gener extends GenericServlet {
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        //打印内容在控制台
        System.out.println("Hello Servlet with terminal");
        //通过流输出数据到浏览器
        servletResponse.getWriter().write( "Hello Servlet with brower");
    }
}

启动服务器后在浏览器中访问得

在这里插入图片描述

(2)实现Servlet接口

除了两个继承抽象类实现Servlet的接口,还有一个通过实现interface Servlet来实现Servlet规范的方法

在这里插入图片描述

实例
创建类Servlet_imp.java ,使其实现Servlet接口
在这里插入图片描述
IDEA中使用快捷键Alt+Shift+Enter实现方法,在service()方法中添加测试代码,并且在类前添上@WebServlet()注释

package www.caijiyuan;

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;

@WebServlet("/Servlet_imp")
public class Servlet_imp implements Servlet {

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {

    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        //通过流输出数据到浏览器
        servletResponse.getWriter().write( "Hello Servlet with brower");
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}

访问浏览器同样可以得到
在这里插入图片描述

(3)在HttpServlet中直接重写doGet()和doPost()方法

我们在调用HttpServlet中service方法时,底层实际上是判断GET请求还是POST请求从而分别调用doGet()和doPost()方法

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();
        long lastModified;
        if (method.equals("GET")) {
            lastModified = this.getLastModified(req);
            if (lastModified == -1L) {
                this.doGet(req, resp);
            } else {
                long ifModifiedSince;
                try {
                    ifModifiedSince = req.getDateHeader("If-Modified-Since");
                } catch (IllegalArgumentException var9) {
                    ifModifiedSince = -1L;
                }

                if (ifModifiedSince < lastModified / 1000L * 1000L) {
                    this.maybeSetLastModified(resp, lastModified);
                    this.doGet(req, resp);
                } else {
                    resp.setStatus(304);
                }
            }
        } else if (method.equals("HEAD")) {
            lastModified = this.getLastModified(req);
            this.maybeSetLastModified(resp, lastModified);
            this.doHead(req, resp);
        } else if (method.equals("POST")) {
            this.doPost(req, resp);
        } else if (method.equals("PUT")) {
            this.doPut(req, resp);
        } else if (method.equals("DELETE")) {
            this.doDelete(req, resp);
        } else if (method.equals("OPTIONS")) {
            this.doOptions(req, resp);
        } else if (method.equals("TRACE")) {
            this.doTrace(req, resp);
        } else {
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[]{method};
            errMsg = MessageFormat.format(errMsg, errArgs);
            resp.sendError(501, errMsg);
        }
    }

实例
创建类Servlet_do.java使其继承自HttpServlet,然后重写doGet()和doPost()方法
在这里插入图片描述
通过上一节我们已经知道了浏览器访问地址是使用GET方法,所以我们在doGet()中添加测试代码,并且在类前添上@WebServlet()注释

package www.caijiyuan;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/Servlet_do")
public class Servlet_do extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        super.doGet(req, resp);
        //通过流输出数据到浏览器
        resp.getWriter().write( "Hello Servlet with brower");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        super.doPost(req, resp);
    }
}

访问浏览器同样可以得到
在这里插入图片描述

以上三种方式都可以实现Servlet规范,使得普通Java类升级成Servlet类,但最简便的方式还是第一种,也就是继承自HttpServlet类

四、Servlet生命周期

有了以上的知识储备,我们就可以梳理一下Servlet的整个生命周期了:由于Servlet没有main()方法,不能独立运行,它的运行完全由Servlet引擎来控制和调度,所谓生命周期,指的就是Servlet容器何时创建 Servlet实例、何时调用其方法进行请求的处理、何时并销毁其实例的整个过程。

  • 实例和初始化时机:当请求到达容器时,容器查找该 Servlet对象是否存在,如果不存在,则会创建实例并进行初始化,如果存在则会直接调用service()方法
  • 就绪/调用/服务阶段:当有请求到达容器,容器调用Servlet对象的 service()方法,此方法在整个生命周期中可以被多次调用;HttpServlet的 service()方法则会依据请求方式来调用doGet()或者doPost()方法。但是,这两个do方法默认情况下,会抛出异常,需要子类去override
  • 销毁时机:当容器关闭时(应用程序停止时),会将程序中的Servlet实例进行销毁。上述的生命周期可以通过Servlet 中的生命周期方法来观察。在Servlet 中有三个生命周期方法,不由用户手动调用,而是在特定的时机由容器自动调用

观察这三个生命周期方法即可观察到Servlet的生命周期

init方法,在Servlet 实例创建之后执行(证明该Servlet有实例创建了)

public void init() throws ServletException {
	System.out.println("创建实例调用");
}

service 方法,每次有请求到达某个Servlet 方法时执行,用来处理请求(证明该Servlet 进行服务了)

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
	System.out.println("service方法调用了");
}

destroy 方法,Servlet实例销毁时执行(证明该Servlet的实例被销毁了)

public void destroy() {
	System.out.println("实例被销毁了");
}

实例

启动服务器在浏览器中访问项目得
在这里插入图片描述
在控制台输出,即是在浏览器访问项目时调用了init()方法(只会被调用一次init()),并且紧接着接受请求调用了service方法
在这里插入图片描述
接着关闭Tomcat服务器,在控制台输出
在这里插入图片描述
Servlet的生命周期,可以更详细的分为四步:Servlet类加载 – >实例化 – >服务 – >销毁
下面我们描述一下Tomcat与Servlet是如何工作的,看看下面的时序图:
在这里插入图片描述

  1. Web Client 向Servlet容器(Tomcat)发出Http请求
  2. Servlet 容器接收Web Client的请求
  3. Servlet 容器创建一个HttpServletRequest对象,将Web Client请求的信息封装到这个对象中
  4. Servlet 容器创建一个HttpServletResponse 对象
  5. Servlet 容器调HttpServlet对象service 方法,把Request与Response作为参数,传给HttpServlet
  6. HttpServlet 调用HttpServletRequest对象的有关方法,获取Http请求信息
  7. HttpServlet 调用HttpServletResponse对象的有关方法,生成响应数据
  8. Servlet 容器把HttpServlet的响应结果传给Web Client

以上就是此小节的所有内容,我们系统的学习了Servlet的概念、实现Servlet规范的多个方法、Servlet的工作流程、生命周期等,为之后Servlet具体对象学习打下了坚实的基础。从下一节开始我们将学习service方法两个形参之一:HttpServletRequest实例的具体操作

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/383584.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode.144. 二叉树的前序遍历

题目 144. 二叉树的前序遍历 分析 这道题目是比较基础的题目&#xff0c;我们首先要知道二叉树的前序遍历是什么&#xff1f; 就是【根 左 右】 的顺序&#xff0c;然后利用递归的思想&#xff0c;就可以得到这道题的答案&#xff0c;任何的递归都可以采用 栈 的结构来实现…

[C++] opencv + qt 创建带滚动条的图像显示窗口代替imshow

在OpenCV中&#xff0c;imshow函数默认情况下是不支持滚动条的。如果想要显示滚动条&#xff0c;可以考虑使用其他库或方法来进行实现。 一种方法是使用Qt库&#xff0c;使用该库可以创建一个带有滚动条的窗口&#xff0c;并在其中显示图像。具体步骤如下&#xff1a; 1&…

使用PyOD进行异常值检测

异常值检测各个领域的关键任务之一。PyOD是Python Outlier Detection的缩写&#xff0c;可以简化多变量数据集中识别异常值的过程。在本文中&#xff0c;我们将介绍PyOD包&#xff0c;并通过实际给出详细的代码示例 PyOD简介 PyOD为异常值检测提供了广泛的算法集合&#xff0c…

【Rust】使用Rust实现一个简单的shell

一、Rust Rust是一门系统编程语言&#xff0c;由Mozilla开发并开源&#xff0c;专注于安全、速度和并发性。它的主要目标是解决传统系统编程语言&#xff08;如C和C&#xff09;中常见的内存安全和并发问题&#xff0c;同时保持高性能和底层控制能力。 Rust的特点包括&#x…

C++构造和折构函数详解,超详细!

个人主页&#xff1a;PingdiGuo_guo 收录专栏&#xff1a;C干货专栏 大家龙年好呀&#xff0c;今天我们来学习一下C构造函数和折构函数。 文章目录 1.构造函数 1.1构造函数的概念 1.2构造函数的思想 1.3构造函数的特点 1.4构造函数的作用 1.5构造函数的操作 1.6构造函数…

洗地机哪个品牌最耐用质量好?耐用的洗地机型号

相较于传统的打扫方式&#xff0c;洗地机的出现可以称得上是懒人福音。一台洗地机就能包办吸、扫、拖所有清洁步骤&#xff0c;节省了大量的打扫时间。不过最近几年洗地机行业涌入的品牌属实有些鱼龙混杂了&#xff0c;至于型号就更是乱七八糟&#xff0c;稍不留神就会白白花了…

深度学习之线性模型

深度学习之线性模型 y w * x模型思路 y w * x b模型思路 y w * x模型 思路 这里求权重w , 求最适合的权重&#xff0c;就是求损失值最小的时候 这里用穷举法:在一个范围内&#xff0c;列出w的所有值&#xff0c;并且计算出每组数据的平均损失值,以w 为横坐标, 损失值为纵坐…

【射影几何15】python双曲几何工具geometry_tools

目录 一、说明二、​环境问题&#xff1a;如何安装三、实现一个简单的例子四、绘制双曲组五、使用有限状态自动机加快速度六、资源和代码 一、说明 Geometry_tools 是一个 Python 包&#xff0c;旨在帮助您处理和可视化双曲空间和射影空间上的群动作。 该包主要构建在 numpy、…

C语言求解猴子分桃子

问题&#xff1a;海滩上有一堆桃子&#xff0c;五只猴子来分。第一只猴子把这堆桃子平均分为五份&#xff0c;多了一个&#xff0c;这只 猴子把多的一个扔入海中&#xff0c;拿走了一份。第二只猴子把剩下的桃子又平均分成五份&#xff0c;又多了 一个&#xff0c;它同样把多的…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Divider组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之Divider组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、Divider组件 提供分隔器组件&#xff0c;分隔不同内容块/内容元素。 子组件 …

2024年湖南省考报名时间及流程,选岗很重要!

注册时间&#xff1a;2024年2月18日9:00-25日17:00 报名时间&#xff1a;2024年2月19日9:00-25日17:00 网上确认时间&#xff1a;2024年2月28日9:00-3月2日24:00 缴费时间&#xff1a;2024年2月28日9:00-3月2日24:00 打印准考证时间&#xff1a;2024年3月11日9:00-15日17:00 考…

漂亮不是工业HMI的追求?我劝你,这个想法要变了

对于工业HMI&#xff08;Human Machine Interface&#xff09;来说&#xff0c;漂亮并不是唯一的追求&#xff0c;但它仍然是一个重要的方面。在工业环境中&#xff0c;HMI的设计需要考虑到使用者的工作效率和安全性&#xff0c;因此功能性和易用性是首要考虑的因素。然而&…

【EAI 015】CLIPort: What and Where Pathways for Robotic Manipulation

论文标题&#xff1a;CLIPort: What and Where Pathways for Robotic Manipulation 论文作者&#xff1a;Mohit Shridhar1, Lucas Manuelli, Dieter Fox1 作者单位&#xff1a;University of Washington, NVIDIA 论文原文&#xff1a;https://arxiv.org/abs/2109.12098 论文出处…

【计算机网络】网络基础入门

需要云服务器等云产品来学习Linux的同学可以移步/–>腾讯云<–/官网&#xff0c;轻量型云服务器低至112元/年&#xff0c;优惠多多。&#xff08;联系我有折扣哦&#xff09; 文章目录 1. 局域网和广域网2. 协议2.1 认识协议2.2 协议分层 3. OSI七层模型和TCP五层&#x…

Ainx-V0.2-简单的连接封装与业务绑定

&#x1f4d5;作者简介&#xff1a; 过去日记&#xff0c;致力于Java、GoLang,Rust等多种编程语言&#xff0c;热爱技术&#xff0c;喜欢游戏的博主。 &#x1f4d7;本文收录于Ainx系列&#xff0c;大家有兴趣的可以看一看 &#x1f4d8;相关专栏Rust初阶教程、go语言基础系列…

vue中watch和computed的不同

第076个 查看专栏目录: VUE ------ element UI Vue.js 中的 watch 和 computed 都是用于监听数据变化并执行相应操作的选项&#xff0c;但它们的使用场景和优劣势有所不同。 两者区别 watch 用于监听一个或多个数据属性的变化&#xff0c;并在变化时执行相应的处理函数。 它…

Windows快捷键大全(包含语音输入、剪切板历史快捷键)

最近发现了微软官网上给出的快捷键大全&#xff0c;并且使用了其中几个新的键盘快捷键&#xff08;语音输入、剪切板历史&#xff09;&#xff0c;确实方便快捷&#xff0c;所以写个博客记录分享一下。 注&#xff1a;windows快捷键大全微软官方已经给出&#xff0c;此处不再赘…

中创ET4410 台式LCR数字电桥 简单开箱测评

最近买了一台LCR电桥&#xff0c;完善一下自己实验室的设备&#xff0c;选了中创ET4410&#xff0c;这款性价比高一点。 1199元在PDD买的&#xff0c;好像胜利的VC4090C也是找中创代工的。 ET4410介绍 本系列LCR数字电桥是采用自动平衡电桥原理设计的元件参数分析仪&#xf…

数据库恢复

文章目录 前言一、事务1.概念2.定义语句3.ACID特性 二、数据库恢复的必要性1.为什么要进行数据库恢复2.数据库恢复机制的作用 三、数据恢复使用的技术1.数据转储2.登记日志文件 四 、不同故障的数据恢复策略1.事务内部的故障2.系统故障3.介质故障 五、具有检查点的恢复技术1.检…

JVM学习记录

JVM基础概念 JVM是一个运行在计算机上的程序&#xff0c;负责编译java字节码文件&#xff0c;支持跨平台特性。 java语言为了通过实时解释实现多平台支持&#xff0c;性能相对于C等语言较低&#xff0c;而JVM提供了JIT即时编译进行性能优化。 JVM与JIT JVM负责解释和执行Ja…