00:00
现在应该能看到屏幕啊。可以看到啊,OK。我们来看一下他的生命周期啊。是这样的,昨天我们有一个同学问了一个很好的问题啊,他说这个老师这个sweat我们好像没有没有六是吧。然后select里面我们创建了什么do get的方法呀,Do p的方法呀,我们也没有调用诶。那么谁帮我们调用的?其实是我们容器帮我们调用的。也就意味着。它的生命周期是他开的容器帮我们去维护的。什么叫生命周期?什么时候创建,什么时候销毁,从从出生到死亡的过程,不就是生命周期吗?啊,所以呢,他就对应我们当中的三个核心的方法。初始化。服务以及销毁。这就是他的生命周期。所以第一个概念,生命周期。什么叫生命周期啊?生命周期。
01:02
就是从出生到死亡。的过程。就是生命周期。所以呢,对应的是什么呢?对应中的三个方法。Init。四。以及destroy。就这样的。再来。那下面呢,我们先来看一下它的生命周期。现在呢,我把这些都关掉。第一个里面,虽然我啥都没写啊,但是我不打算在里面写,我们最好还是新建第二个,这样大家好复习啊。第一个我们里面是空的,打开看一下。是吧,同学们我啥都没写啊,这个C直角都可以删掉啊,都没啥用好。继续啊,来接着看。我们新建一个代零二。
02:02
我们用它来研究生命周期。演示斯特的生命周期好。我们让他继承。继承。HTTP。就这样吧。那么第一个方法叫init方法,咱们把它重写一下。在这个力的方法里面,在这个应力的方法里面,我们就打印一句话,正在初始化行吗?同学们,我们就打印一句话,然后呢,我们再重写一下service方法。老师,你怎么不重写do get do了?其实我们重写service也是一样的,同学们。是不是重写service就意味着不管你发的是啥请求,我都会调用service啊?是吧,同学们,只不过在人家service方法的内部,它才会再去细分嘛。没问题吧,行,我就重启了啊。好,答一句话,Service。啊,或者说正在服务。
03:02
正在服务。再来,我再重写一个方法,叫destroy。这个叫销毁方法。或者叫正在销毁啊。正在销毁。行,这个我就把它写完了,三个核心的方法,那咱们来配置一下呗。回到web X文件,我们来配置一下。好。代零二。零二。好。零二行mapping。好大零二。那我就写个代码零行不行?同学们就这样的,当然了,我们也可以把所有的标签放一块,把所有所有的s mapping标签放一块也行啊。这个随便你啊。你看这是不是也是可以的,把所有的卖品全放一块啊,这也是没问题的,行吧。我们来启动一下啊,把它关掉,重新再来启动一次。
04:03
什么?只写一个卖品标签是什么?你说这两个只写一个。把这个删掉哦,这个咱们同学想象力好丰富啊,啊说的把这个删掉,这不行的。那你这里面就有两个name了是吧,两个幼儿partner了是吧?同学们这肯定不行的啊,这是不行的。啊,我以为我以为咱们同学说的是另外一个话题啊,我既然提到这个,让我想到另外一个,我就延伸一下我们一个。可以对应多个mapping。这是允许的啊,我写一下给大家看一下。一个斯对应的是三个斯卖品,那这边叫DA01 da01101。也就是一个它对应的是三个白屏,你发给零幺也是它响应,发给011也是它响应,发给代012也是它响应。能听懂吗?那有人会说,老师这样的配置有什么实际的意义呢?它其实是有意义的,同学们。
05:03
我们可以在当中去获取你到底是通过哪一个URL请求过来的。根据你不同的URL发给我发的请求,我可以执行不同的业务逻辑。啊,这个是可以的,行,咱们暂时先不再继续延伸了,好不好,我们先再回到我们主题上来,我先删掉啊,反正提到这咱们就稍微说一下。现在已经启动好了,没问题啊。好,全部关掉。我们现在呢,我们打开网页,我们要访问的是不是DEMO02同学们。好,我们访问一下啊,代码零二。敲回车。你看一下它是不是有正在初始化,正在服务。请问如果我在这边,我再次敲回车,是不是意味着我又发了一个请求?我又发了个请求给戴林奥。它又显示正在服务我刷新,是不是也是意味着再发一次请求?发请求,发请求,发请求,你看他永远都是服。
06:03
有人有人说老师你把浏览器关掉了无所谓。你再打开一个新的什么IE浏览器呢?无所谓,它永远都是正在服务。只有我们第一次发请求的时候,它显示正在初始化,表示他出生了吗?表示他出说就绪了嘛。好。那么永远都是正在服务。那什么时候销毁呢?我们默认情况下,随着我们容器的销毁,S它会销毁。所以我们把容器停一下,点这个。知道。看到了吗?那么这个就销毁掉了。好,我们来稍微先小结一下,回到这边来。司法的生命周期。默认情况下。默认情况下。第一次发请求啊,第一次。
07:00
第一次接受请求。请求时。这个会进行实例化。初始化。好不好,会进行实例化,初始化。然后。服。那么。从第二次请求开始,那么每一次都是服务,是不是同学们?好,然后第三点是当容器关闭时,当容器关闭时其中的所有的实例。啊的实力会被销毁。啊,调用销毁方法。是吧,同学们好。实例化。调用构造方法。初始化。调用init方法。服务。调用service方法行吗?同学们,它就是这样的,那也就说老师这个实例化,我没见到实例化。
08:05
这是我们Tom盖在底层使用反射帮我们做的实体化。它是使用反射做的实体化。我们把代码零二,我们把它的构造方法写出来,你看一下。Public。零。这是不是他构造方法,咱们打印一句话,正在实例话。行不行,同学们,我们把这玩意儿把它写上去。啊,写上去之后我看一下啊,写上去之后估计我得重启啊,不重启估计不行。好看一下啊。你看它会不会有一个正在实例化的过程。所以说啊,默认情况下,我们这三句话。通过啊。通过实例。
09:04
啊,通过案例我们发现,我们发现什么呢。的实力。实力啊。他们盖的只会。只会。创建一个是不是啊,所有的请求都是这个实例去响应,没错吧,同学们。啊,我们要得出这个结论。好,把这边全部清空掉,我们回到浏览器,我把这些就全部都关掉吧。好,我们只留这一个啊,来,我们返回代码,零二撬回车,注意看俏回车,你看是不是有正在实例化,正在初始化,正在服务,那你再怎么刷新它都不会有实例化和初始化的过程嘛。就是这样的。好了。我把这个构造方法,我把它改成private。我把它修改成profit,我刷新一下,让他们给他重启一下啊。我们来看一下。
10:13
好了,他已经启动好了,我们来看一下啊。我现在请求单零二,我敲回车啊敲回车。报错了。嗯,他报了一个500的错误,500这个错误咱们暂时先写到这儿啊。瑞,我写到最下面啊。最下面。500。这个是服务器内部错误。啊,表示服务器内部代码有问题啊,这叫内部错误,行仔细的读一下后面的这个信息。Error。这个叫instance实例,它的一个动词。不能够创建某某某这个类的这个实例。不能创建这个实例。啊,就这个意思。他为什么不能创建的实例cannot access access指的是叫访问。
11:04
Cannot不能够访问一个member,一个成员,什么成员?不能访问它里面的一个成员,With mod file modify指的是访问修饰符。不能访问一个以private修饰的这么一个成员,不就是构造方法吗?是吧,同学们,所以你也就能够知道,通过这个我们也就能够知道,其实啊通们盖的底层,它也是通过反射帮我们去调用这构造方法,是吧,同学们帮我们定用各多方法来帮我们完成实例化。啊,所以其实并没有什么好神奇的。行。Get public啊?所以再回到我们这边来,我们要记住这个结论啊,通过案例我们发现serve实例,Tom盖只会创建一个,所有的请求都是在这个实例啊,都是这一个实例。去响应的。默认情况下啊,默认情况就不写了吧啊,然后呢,或者写一下吧啊,默认情况下,默认情况下。
12:01
第一次请求时。Tomcat。才会。去实例化、初始化,然后再服。好把它写到了啊。好,默认情况下,第一次请求的时候,他们盖的财务就实体化,初始化,然后再服,这样的好处是什么?这样的好处是什么?是不是可以提高Tom get,或者叫提高服务器,提高系统的启动速度?是不是提高我们系统的。启动速度。这样的缺点是什么?这样的缺点是什么?你系统启动速度快了。
13:00
但是人家第一次请求过来的时候。你是不是要急急忙忙的去创建实力,去初始化?那么对于人家第一次用户而言的话,他这个等待的时间是不是要长一点。哎,大家想想是不是这样的。啊,第一个用户发请求的时候,他等待的时间要长一点,以后就快了是吧,所以对于第一个用户是不公平的。那么这样的缺点是什么呢?缺点就是说第一次请求时啊,第一次请求时耗时较长。现在大家感觉不到,因为咱们现在系统太简单了,是即使是实例化出这个时间,你基本上忽略不计,但如果这样的这样的实例如果多了之后,那这个其实就能够体现的体现的很明显了。啊,所以说第一次请求时耗时是较长的。是吧,同学们因为需要急急忙忙的去实例化,去初始挖嘛,因此我们就得出个结论啊。因此。因此得出结论。啊,因此我们就得出结论,如果需要。
14:00
如果需要。提高系统的启动速度。啊,当前默认情况就是这样。如果需要提高,听好了啊,如果需要提高。相应速度。我们应该设置的初始化时机。我们应该要设置的初始化时机,因此下面我们就来看一下它的初始化时机。第四个我们来看一下。的初始化时机。默认情况下。我们是在第一次请求时会被初始化。默认是第一次发请求时。啊摸第一次接收吧。接受请求时。实例化、初始化。好,再来我们可以通过,我们可以通过什么呢?我们可以通过一个值。
15:03
回到这里面来。Mapping。稍等一下啊。呃斯,这是零幺,这是丹零二,好,我们来看一下啊。我这边有个叫。Load on startup。不着急,一个一个解释,大up叫启动。漏叫加载。也就意味着我啥时候启动呢,我什么时候加载呢?好,这里面可以设置一个数字,我设置个一。数字越小,启动的时间越靠前。数字越小,启动的时间越靠前。我们可以写零,可以写一,可以写二写三啊,尽量的不要写负数。啊,记住最小值写零就可以了,那咱们写E也行。
16:00
写一也没有问题的啊,这个叫漏洞up。这玩意儿。啊,漏洞三好。这边有的啊,叫M叫零有的啊好。所以来。我们写了一个一。我就写了这一项。我们现在呢,我们再来启动一次看一下啊。启动一下。好,他启动的时间咱们来补一下啊,我们可以通过。Load on startup。来设置启动启动的先后顺序。假设我这里面有多个嘛,我把他们的漏洞startup写成12345,它就会按照12345的顺序进行启动,行吗?同学们好。这个关掉啊,咱们直接访问代码零二就可以了,行啊,现在我是不是页面上我根本没操作啊。咱们把这个控制台打开看一眼。看到了吗?这个信息里面,这是不是他们盖启动的过程啊。
17:01
最后我们通盖会启动好吗?那你看在这个过程里面是不是就已经实例化初始化了。我没有做其他事情啊,我现在还没开始访问呢,是吧,同学们,我在浏览器里面访问一下,敲回车。跳回车,你看一下是不是就已直接正正在服务了,这是我第一次发请求,他是不是就已经服务了。能体现这个差别不?应该能看出来个差别啊,所以我们说一下。我们可以通过漏洞startup来设置启动的先后顺序。数字越小。啊,启动越靠前。啊,最小值零。好,我们要说一下。好了,所以我们刚刚就看到了。我们把这玩意儿漏洞设置为数字一,那你就会发现它随着Tom盖的容器的启动,它已经实例化,初始化结束了。那你想想,我们在Tom盖的容器启动的过程里面,它要把一个一个的发来的实例去实例化,去初始化,那是不是启动的时间一定会延长啊。
18:08
但是你想想好处是什么?我第一个用户发请求,是不是就直接进入服务了?是吧,同学们,所以我的响应速度,应该用户的体验会更好。啊,大不了我启动的时间稍微等一等嘛,但是我后面的体验会更好,就这意思。好,这个叫low startup。OK,这是我们这一点要说的,再来。再来。我们刚刚啊,这是我们说的第一个生命周期,第二个是默认情况下啊,它会执行这些操作,那么通过案例呢,我们会发现,然后呢,我们讲的就叫初始化,好最后一点。最后一点。在容器中。是。戴笠的。县城不安全的。
19:03
啊是两点,在容器当中,它是单立的,它是线程不安全的。单例指的是什么?是不是所有的请求过来,我这个DEMO02,我这个零幺是不是在通容器里面只会创建一个实例啊?不管是你们哪个浏览器,哪个客户端来访问我,我都是同一个实例来给你们做响应的,是吧,同学们这叫单例的,叫单个的实例。第二点大家可能不太好理解,叫线程不安全的。我要给大家解释一下什么叫线程不安全。我们通过一个图。咱们一起来把它看一下。这是我的通盖的容器。这是我的客户端。好了,那么在我的Tom盖的容器里面,我有一个S实例。我就画到这儿。这是一个上的实例。好。然后呢,这个塑料的实例里面呢,这个塑料的实例里面呢,它有个变量。
20:04
它有一个变量。好,我们把它写在这儿。这个变量假设叫number,我意思一下啊,写个叫number int成员变量。Public number假设等于一。那下面他肯定还会有其他的方法,比如说多钙的方法吗。啊,肯定还会有什么do push的方法吗?等等等等啊,会有很多的方法,行,咱们先不管它。那么。我把这个写全了啊,要写要不就写全了吧。这是个。好在这里面。那我就随便写一个吧,比如说这是一个。他的代码。我这个程序变量啊,这两个方法随便嘛,随便在哪个方法里面,或者就是service方法吧,都可以啊service方法public VO service行吗?同学们在这方法里面我有我有做判断if number。如果number等于等于一,我要做一件事情。
21:04
E。啊,如果number或者叫else吧,简单一点,Else。Else,我会做其他事情。就这样。同学们。我为什么说是县城不安全的来?现在这是第一个客户端,这个叫客户端一。客户端一就浏览器嘛。再来第二个客户端。客户账号。客户端二。行第一个客户端访问他。对它进行访问,访问这个色类的实例。他访问这个的实例。哦,读到那么的一没错。然后准备执行这某一个service方法。它执行的是if。
22:00
啊,衣服里面做操作,那没有问题,这是正常现象,好听好了啊听好了。客户端一。给他发请求,这是不是相当于发了一个socket请求啊,Socket的这个TC pip协议在网上是不是有叫HTTP协议这一层啊?是吧,那行,发了个请求过来了。发了个请求过来读到,那么等于一,那么我要去执行if,那么等于等于一的时候,我要执行一件事情,好,这是一个线程。我们叫线程一。县城一。发的请求。那么听好了,这边又有个县城。这个线程他也会给这个发请求。他也会给他发请求。那么他在发请求的时候,他会去做一些事情。他当然也会去读到number。线程二他也会去读到number,但是呢,他就去执行里面的其他一些事情,他线程二可能会把我们number的值改掉。
23:05
通过我这边写红字写的这啊,通过现场。执行不同路径的。代码。将。Number的值修改为二。或者修改为五吧,随便意思一下啊,总之是一个不等于一的一个值。那么我线程一听好了。我现存一。在执行读number等于一的时候,然后我进入了service。刚刚准备执行if这个判断。本来我正常的路径,我认为我读到的是一,那么我就要执行if,那么等于等于一成立吗?我就要执行这里面代码,但是在if执行之前,这个瞬间线程二把number值改成了五。那请问一下这个if还成立吗?这个if就不成立了,那是不是就把线程E的这个执行的路径修改掉了。会导致。
24:01
此时会导致县城一。执行的路径发生变化。啊,这个说的稍微有一点点抽象了。啊,但是我希望通过这个案例,大家好好的去琢磨一下,有两个线程同时执行一块代码。啊,这就像什么呢?那么一等一这是什么?这个是叫就想象一下这是两个人啊,这个是一个厕所,这个厕所这边放卫生纸呢,啊,放着卫生纸是吧,这个县成一拉肚子啊,从远处一看,这个厕所里面有纸呢,我就不用再回去拿纸了是吧?赶紧往厕所奔。快要奔到厕所这边之前,现场过来把纸迅速的拿拿走了。那县城一就傻眼了。他本来想的是我是这个油纸,我就要进来直接直接这个开工工作是吧,结果现在啊,在这个中间把纸拿掉了。是不是这样的,在县城一工作的时候,他把某一个值改变掉了。
25:02
啊,这是斯存在的一种现象,因为它是单个实例,我们所有的县城都共用这一个实例。就会出现叫所谓的叫县城不安全,我们把这个现象称之为叫县城不安全。第一步,大家现在现在听得懂什么叫线程不安全,就是一个线程在访问的时候,按照正常流程是没有错的,突然我执行的过程当中,另外一个线程把某一个程序变量改掉了。而我需要根据这个程序变量去做一些判断依据是吧?同学们好,这叫线程不安全。好,再回到这边来。单利咱们就不解释了啊。简单写一下,单利指的是所有的请求。所有的请求啊,都是同一个实例去响应。行吧,同学们,这比较简单,第二个是线程不安全。啊,现在判决指的是。一个线程需要根据这个实例中的某个成员变量值。
26:03
值去做判断啊,去做逻辑判断。但是在中间啊,在但是在中间啊,某个时机。某个时间另一个线程。改变了这个成员。变量的值。从而导致第一个线程的执行路径发生了变化,是吧,同学们?发生了变化,就这样的啊,我们称之为叫县城不安全。那么第三我们就要说如何啊,我们第三个就是我们已经知道了是线程不安全的。给我们的,给我们的启发是。尽量的不要在。中定义成员变量。是吧,同学们。如果非要去定义乘以变量。
27:03
如果不得不定义成员变量。那么不要去啊,不要去根据成员变量的。值。做一些逻辑判断。啊,那么不要去修改。稍等一下啊。我们看一下啊。嗯,不在这里面VR我看一下啊,啊这边有啊。第一个。不要去修改成员。变量的值。啊,这第一点。第二点是。第二点是根据乘以变量的值啊,不要去。不要去根据乘以变量的值做一些逻辑判断是吧,同学们。就这样子,这叫县城不安全。
28:00
OK,那么这是他的生命周期,我们需要给他去介绍的。
我来说两句