servlet的本质是啥,它是如何工作的?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了servlet的本质是啥,它是如何工作的?相关的知识,希望对你有一定的参考价值。
Servlet(Server Applet),全称Java Servlet,本质上就是一个java类。
servlet工作原理:
1、创建servlet(继承HttpServlet,重写方法)。
2、部署servlet(servlet是组件,必须放在容器中,使用容器访问),第一:把.class文件放在WEB-INF下的classes文件夹里,第二:配置web.xml文件。
3、启动服务器,url直接在浏览器地址栏中访问servlet,调用doGet方法。
Servlet运行于支持Java的应用服务器中。从原理上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。
最早支持Servlet标准的是JavaSoft的Java Web Server,此后,一些其它的基于Java的Web服务器开始支持标准的Servlet。
工作模式:
1、客户端请求该 Servlet;
2、加载 Servlet 类到内存;
3、实例化并调用init()方法初始化该 Servlet;
4、service()(根据请求方法不同调用doGet() 或者 doPost(),此外还有doHead()、doPut()、doTrace()、doDelete()、doOptions());
5、destroy();
6、加载和实例化 Servlet。这项操作一般是动态执行的。然而,Server 通常会提供一个管理的选项,用于在 Server 启动时强制装载和初始化特定的 Servlet;
7、Server 创建一个 Servlet的实例;
8、第一个客户端的请求到达 Server;
9、Server 调用 Servlet 的 init() 方法(可配置为 Server 创建 Servlet 实例时调用,在 web.xml 中 <servlet> 标签下配置 <load-on-startup> 标签,配置的值为整型,值越小 Servlet 的启动优先级越高);
10、一个客户端的请求到达 Server;
11、Server 创建一个请求对象,处理客户端请求;
12、Server 创建一个响应对象,响应客户端请求;
13、Server 激活 Servlet 的 service() 方法,传递请求和响应对象作为参数;
14、service() 方法获得关于请求对象的信息,处理请求,访问其他资源,获得需要的信息;
15、service() 方法使用响应对象的方法,将响应传回Server,最终到达客户端。service()方法可能激活其它方法以处理请求,如 doGet() 或 doPost() 或程序员自己开发的新的方法;
16、对于更多的客户端请求,Server 创建新的请求和响应对象,仍然激活此 Servlet 的 service() 方法,将这两个对象作为参数传递给它。如此重复以上的循环,但无需再次调用 init() 方法。一般 Servlet 只初始化一次(只有一个对象),当 Server 不再需要 Servlet 时(一般当 Server 关闭时),Server 调用 Servlet 的 destroy() 方法。
“列表理解”和类似的意思是啥?它是如何工作的,我该如何使用它?
【中文标题】“列表理解”和类似的意思是啥?它是如何工作的,我该如何使用它?【英文标题】:What does "list comprehension" and similar mean? How does it work and how can I use it?“列表理解”和类似的意思是什么?它是如何工作的,我该如何使用它? 【发布时间】:2016-04-22 12:22:38 【问题描述】:我有以下代码:
[x ** 2 for x in range(10)]
当我在 Python shell 中运行它时,它会返回:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
我已经搜索过,这似乎被称为 列表推导,类似地,似乎有 set/dict 推导和生成器表达式。但它是如何工作的呢?
【问题讨论】:
【参考方案1】:From the documentation:
列表推导式提供了一种创建列表的简洁方式。常见的应用是创建新列表,其中每个元素是应用于另一个序列或可迭代的每个成员的某些操作的结果,或者创建满足特定条件的那些元素的子序列。
关于您的问题,列表理解与以下“普通”Python 代码的作用相同:
>>> l = []
>>> for x in range(10):
... l.append(x**2)
>>> l
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
如何在一行中写出来?嗯...我们可以...可能...使用map()
和lambda
:
>>> list(map(lambda x: x**2, range(10)))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
但是仅仅使用列表推导不是更清晰更简单吗?
>>> [x**2 for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
基本上,我们可以用x
做任何事情。不仅x**2
。比如运行x
的方法:
>>> [x.strip() for x in ('foo\n', 'bar\n', 'baz\n')]
['foo', 'bar', 'baz']
或者使用x
作为另一个函数的参数:
>>> [int(x) for x in ('1', '2', '3')]
[1, 2, 3]
例如,我们还可以使用x
作为dict
对象的键。让我们看看:
>>> d = 'foo': '10', 'bar': '20', 'baz': '30'
>>> [d[x] for x in ['foo', 'baz']]
['10', '30']
组合怎么样?
>>> d = 'foo': '10', 'bar': '20', 'baz': '30'
>>> [int(d[x].rstrip('0')) for x in ['foo', 'baz']]
[1, 3]
等等。
您也可以在列表推导中使用if
或if...else
。例如,您只需要range(10)
中的奇数。你可以这样做:
>>> l = []
>>> for x in range(10):
... if x%2:
... l.append(x)
>>> l
[1, 3, 5, 7, 9]
啊,这太复杂了。下面的版本呢?
>>> [x for x in range(10) if x%2]
[1, 3, 5, 7, 9]
要使用if...else
三元表达式,您需要将if ... else ...
放在x
之后,不是 在range(10)
之后:
>>> [i if i%2 != 0 else None for i in range(10)]
[None, 1, None, 3, None, 5, None, 7, None, 9]
你听说过nested list comprehension吗?您可以将两个或多个for
s 放在一个列表理解中。例如:
>>> [i for x in [[1, 2, 3], [4, 5, 6]] for i in x]
[1, 2, 3, 4, 5, 6]
>>> [j for x in [[[1, 2], [3]], [[4, 5], [6]]] for i in x for j in i]
[1, 2, 3, 4, 5, 6]
让我们谈谈第一部分,for x in [[1, 2, 3], [4, 5, 6]]
,它给出了[1, 2, 3]
和[4, 5, 6]
。然后,for i in x
给出1
、2
、3
和4
、5
、6
。
警告:你总是需要把for x in [[1, 2, 3], [4, 5, 6]]
之前 for i in x
:
>>> [j for j in x for x in [[1, 2, 3], [4, 5, 6]]]
Traceback (most recent call last):
File "<input>", line 1, in <module>
NameError: name 'x' is not defined
我们还有set comprehensions、dict comprehensions和generator expressions。
集合推导和列表推导基本相同,但前者返回的是集合而不是列表:
>>> x for x in [1, 1, 2, 3, 3, 1]
1, 2, 3
同理:
>>> set([i for i in [1, 1, 2, 3, 3, 1]])
1, 2, 3
dict comprehension 看起来像一个集合推导,但它使用key: value for key, value in ...
或i: i for i in ...
而不是i for i in ...
。
例如:
>>> i: i**2 for i in range(5)
0: 0, 1: 1, 2: 4, 3: 9, 4: 16
它等于:
>>> d =
>>> for i in range(5):
... d[i] = i**2
>>> d
0: 0, 1: 1, 2: 4, 3: 9, 4: 16
(i for i in range(5))
是否提供 元组?不!,它是generator expression。它返回一个生成器:
>>> (i for i in range(5))
<generator object <genexpr> at 0x7f52703fbca8>
同理:
>>> def gen():
... for i in range(5):
... yield i
>>> gen()
<generator object gen at 0x7f5270380db0>
您可以将其用作生成器:
>>> gen = (i for i in range(5))
>>> next(gen)
0
>>> next(gen)
1
>>> list(gen)
[2, 3, 4]
>>> next(gen)
Traceback (most recent call last):
File "<input>", line 1, in <module>
StopIteration
注意:如果您在函数内使用列表推导,如果该函数可以循环生成器,则不需要[]
。例如sum()
:
>>> sum(i**2 for i in range(5))
30
相关(关于生成器):Understanding Generators in Python。
【讨论】:
三元表达式x if cond else y
确实与列表推导没有任何特别的关系——任何有效的表达式都可以在列表压缩中使用——三元表达式是许多 python 表达式之一。跨度>
@AChampion:是的,我在回答中提到了这一点,因为我在学习列表推导时尝试了[i for i in x if i else y]
,但它不起作用。经过一番研究,我明白我必须改用[i if i else y for i in x]
。所以我想如果我在这里提到它,那么其他人可以避免我之前遇到的问题。【参考方案2】:
有列表、字典和集合推导,但没有元组推导(尽管探索“生成器表达式”)。
它们解决了 Python 中的传统循环是语句(不返回任何内容)而不是返回值的表达式的问题。
它们不是所有问题的解决方案,可以重写为传统循环。当需要在迭代之间维护和更新状态时,它们会变得很尴尬。
它们通常包括:
[<output expr> <loop expr <input expr>> <optional predicate expr>]
但可以以许多有趣和奇异的方式扭曲。
它们可以类似于传统的map()
和filter()
操作,它们仍然存在于 Python 中并继续使用。
如果做得好,他们的满意度会很高。
【讨论】:
这让我很开心:When done well, they have a high satisfaction quotient.
【参考方案3】:
我最近看到了很多关于列表理解如何工作的困惑(关于其他 SO 问题和来自同事的)。一点点数学教育可以帮助了解为什么语法是这样的,以及列表推导的真正含义。
语法
最好将列表推导式视为集合/集合上的谓词,就像我们在数学中使用集合构建器表示法一样。这个符号对我来说实际上感觉很自然,因为我拥有数学本科学位。不过别提我了,Guido van Rossum(Python 的发明者)拥有数学硕士学位,并且有数学背景。
设置生成器符号速成课程
以下是集合生成器符号的工作原理(非常基础):
因此,此集合构建器表示法表示严格为正的数字集(即[1,2,3,4,...]
)。
混淆点
1) 集合构建器表示法中的谓词过滤器只指定我们想要保留哪些项目,列表理解谓词做同样的事情。您不必包含省略项目的特殊逻辑,除非包含在谓词中,否则它们将被省略。空谓词(即末尾没有条件)包括给定集合中的所有项目。
2) 集合生成器表示法中的谓词过滤器放在最后,列表推导中也是如此。(一些)初学者认为像[x < 5 for x in range(10)]
这样的东西会给他们列表[0,1,2,3,4]
,当实际上它输出[True, True, True, True, True, False, False, False, False, False]
。我们得到输出[True, True, True, True, True, False, False, False, False, False]
,因为我们要求Python 为range(10)
中的所有 项评估x < 5
。没有谓词意味着我们从集合中获取所有内容(就像在集合构建器表示法中一样)。
如果您在使用列表推导时将集合构建器符号放在脑海中,它们会更容易接受。
HTH!
【讨论】:
【参考方案4】:如果您更喜欢以更直观的方式了解正在发生的事情,那么这可能会有所帮助:
# for the example in the question...
y = []
for x in range(10):
y += [x**2]
# is equivalent to...
y = [x**2 for x in range(10)]
# for a slightly more complex example, it is useful
# to visualize where the various x's end up...
a = [1,2,3,4]
b = [3,4,5,6]
c = []
for x in a:
if x in b:
c += [x]
# \ \ /
# \ _____\______/
# \ / \
# \/ \
# /\ \
# / \ \
# / \ \
c = [x for x in a if x in b]
print(c)
...产生输出[3, 4]
【讨论】:
【参考方案5】:简介
列表推导式是一种在 Python 中创建列表的高级声明式方法。理解的主要好处是可读性和可维护性。很多人觉得它们非常易读,即使是以前从未见过它们的开发人员通常也能猜出它的含义。
# Snippet 1
squares = [n ** 2 for n in range(5)]
# Snippet 2
squares = []
for n in range(5):
squares.append(n ** 2)
代码的两个 sn-ps 将产生 squares
等于 [0, 1, 4, 9, 16]
。
请注意,在第一个 sn-p 中,您键入的是声明您想要什么样的列表,而第二个是指定如何创建它。这就是为什么理解是高级和声明性的。
语法
[EXPRESSION for VARIABLE in SEQUENCE]
EXPRESSION
是任何 Python 表达式,但通常会在其中包含一些变量。此变量在VARIABLE
字段中说明。 SEQUENCE
定义了变量枚举值的来源。
考虑片段 1,[n ** 2 for n in range(5)]
:
EXPRESSION
是 n ** 2
VARIABLE
是 n
SEQUENCE
是 range(5)
请注意,如果您检查 squares
的类型,您会发现列表理解只是一个常规列表:
>>> type(squares)
<class 'list'>
更多关于表达式
表达式可以是任何简化为值的东西:
算术表达式,例如n ** 2 + 3 * n + 1
像f(n)
这样的函数调用,使用n
作为变量
像s[::-1]
这样的切片操作
方法调用bar.foo()
...
一些例子:
>>> [2 * x + 3 for x in range(5)]
[3, 5, 7, 9, 11]
>>> [abs(num) for num in range(-5, 5)]
[5, 4, 3, 2, 1, 0, 1, 2, 3, 4]
>>> animals = ['dog', 'cat', 'lion', 'tiger']
>>> [animal.upper() for animal in animals]
['DOG', 'CAT', 'LION', 'TIGER']
过滤:
最终列表中元素的顺序由SEQUENCE
的顺序决定。但是,您可以过滤掉添加 if
子句的元素:
[EXPRESSION for VARIABLE in SEQUENCE if CONDITION]
CONDITION
是一个计算结果为True
或False
的表达式。从技术上讲,条件不必依赖于VARIABLE
,但它通常使用它。
例子:
>>> [n ** 2 for n in range(5) if n % 2 == 0]
[0, 4, 16]
>>> animals = ['dog', 'cat', 'lion', 'tiger']
>>> [animal for animal in animals if len(animal) == 3]
['dog', 'cat']
另外,请记住 Python 允许您编写除列表之外的其他类型的推导:
字典理解 设置理解【讨论】:
以上是关于servlet的本质是啥,它是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章