Servlet : 在 Javaweb 中 非常的 重要, 在 整个 的 Javaweb 的知识体系中 都是 围绕 Servlet 来转的. (非常重要. 重点掌握.).
## Servlet : server applet
* 概念: 运行在 服务端的 小程序.
* Servlet 就是一个 接口, 定义了 Java 类 被 浏览器 访问到(被 tomcat 识别) 的 规则,
* 将来 我们 自定义一个类, 实现 Servelet 接口, 复写方法. (tomcat 就可以识别 到, 浏览器 就可以访问到, 这个类 就 称为 Servelet )
只要 我 这个 Java 类 实现了 Servlet 这个 接口(规则), 就可以 被 tomcat 识别.
动态资源: 每个 用户 访问 同一个 资源, 得到的 反馈 可能不一样, 怎么 不一样呢?
里面 加了 逻辑性的 代码, 例如: 判断 如果 是张三 这个 用户 访问, 回馈 什么信息, 如果是 李四 这个 用户 访问 , 回馈什么 什么信息, 这就造成了 每个 用户 访问的 资源 不一样.
而 这个 逻辑性的 代码 需要用 Java 代码 编写.
规则 一般在 Java 表示形式 为 接口, 在 tomcat 中 所能识别的 规则 就是 servelet.
* 所以 我们 定义的 Java 类 要去 实现 servelet , 称为 servelet 接口类. 才能 被 tomcat 所识别.
* 这个 Java 类 依赖于 服务器 才能运行, 相当于 tomcat 执行它 (反射).
* 服务器 软件: 接收 用户的请求, 处理请求, 做出 响应.
* web 服务器软件: 接受用户的 请求, 处理请求, 做出响应. (用户 通过 浏览器 发出请求.)
Servlet 接口 要 查询 JavaEE 文档.
* 快速入门 :
Servlet 将来得 运行在 tomcat , 也就是 web 服务器里面, 先得 将 服务器 弄起来. (tomcat 已经配置完毕. )
1. 创建 JavaEE 的 项目.
2. 定义一个类, 实现 Servlet 接口.
* public class ServeletDemo1 implements Servlet {
3. 实现 接口中的 抽象 方法.
4. 配置 Servelet (不配置 一下, 浏览器 上哪, 或者说 tomcat 上哪找 你这个 Java 类. )
* 在 web / WEB-INF / web.xml 中 配置 Servlet:
* 写在 根标签 里面..
*
<servlet>
<servlet-name>demo1servlet-name>
<servlet-class>cn.itcast.web.servelet.ServeletDemo1servlet-class>
servlet>
<servlet-mapping>
<servlet-name>demo1servlet-name>
<url-pattern>/demo1url-pattern>
servlet-mapping>
*** 通过 这个 资源名称 映射 这个类的 访问路径.
demo1 对应的 是哪个类 . (配置 这个类的 全类名. )
// *** 访问: http://localhost:8080/demo1
之前 将 虚拟 目录 改为了 / 这样 就不用写 虚拟目录 直接 写 项目的 名称, 比较方便. 项目多了. 就不合适, 修改为 例如: /day13_tomcat
http://localhost:8080/day13_tomcat/demo1
将 每个 项目的 项目名 设置为 虚拟目录(路径), 这样用 比较合适.
* Tomcat 执行 Servlet 的执行原理 :
1. 当 服务器 接收到 客户端 浏览器 的 请求后, 会解析 请求 URL 路径, 获取访问的 Servlet 的 资源路径. (/demo1);
2. 查找 web.xml 文件, 是否 有 对应的 标签体内容 与 这个 资源的 路径一致.
3. 如果有, 则 再找到 对应的 全类名.
4. tomcat 会将 字节码 文件 加载进 内存, 并且 创建 其 对象. ]
5. 调用 其 方法.
* Servlet 中的 生命周期 ( 方法 ): (*** 重点掌握 这三个 方法)
1. 被创建 : 执行 init() 方法, 只 执行一次. (换句话说, Servlet 只会被 创建 一次. )
* Servlet 什么 时候 被创建?
* 默认情况下, 第一次 被访问时, Servlet 被创建.
* 可以指定 Servlet 的创建时机 .
在 标签下 配置 标签. (负数 或者 正整数.)
例如: 有的 Servlet 加载的 资源比较多. *** init () 方法 是用来 加载 资源的. (如果 太多, 用户 访问 就有可能 比较慢. )
有的 Servlet 在 执行之前, 需要 依赖于 其它的 Servlet 资源, 这时 就可以将 其它的 Servlet 在 服务器 启动时 就被 创建(加载资源.)
* Servlet 的 init() 方法, 只执行 一次, 说明 一个 Servlet 在 内存中 只存在 一个对象, Servlet 是 单例的. 内存中 这一个 Servlet 就只有 一个 对象.
*** 在 多个 线程 访问 一个 对象资源的 时候, 可能 发生 线程 安全问题,
* 多个 用户 同时 访问时, 可能 存在 线程安全问题.
* 加 同步代码块(锁), 不可取: 例如 这个 方法 是用来 买票的, 加了锁, 当多个 用户 同时 买票时, 一个 用户 没买完, 另一个 用户就不能买, 就得 一直等着, 效率 太慢, 不合适, 性能 影响 太严重.
解决方案:
尽量 不要在 Servlet 中 定义 成员变量, 可以在 方法中,例如 service 方法中 定义 局部变量, 局部变量 每一次 方法的 进栈, 都会 有一个 局部变量, 这个 局部变量 就不是 共享的了.
即使 定义了 成员变量, 也不要 对其 进行 赋值, 修改值 操作. (如果 仅仅 只是 获取 这个 值 , 还是没有问题的. int i = 3; 无论 拿 多少次 这个值, 依然 不会变. 不会有问题. )
2. 提供服务 : 执行 service( ) 方法, 每次 访问 都会执行, 执行 多次.
* 每次 访问 Servlet 时, Service 方法 都会被 调用一次.
3. 被销毁 : 执行 destroy( ) 方法, 只执行 一次. (换句话说, Servlet 只会被 杀死 一次. (释放资源吗? ))
* Servlet 被销毁时 执行. 当服务器 关闭时, Servlet 被 销毁,
* 只有 服务器 正常关闭时, 才会执行 destroy 方法, 不正常关闭, 例如 强制关闭, 是不会 执行 这个 方法的.
* destroy 这个 方法 在 Servlet 销毁之前 执行, 一般用于 释放资源 . (就像交代 临终 遗言一样.)
* destroy 这个 方法 用来 释放资源, init 方法 用来 加载 资源.
*** 只要 一个 Java类 实现了 Servlet 接口, 我们 就称这个类 为 一个 Servlet .
*** Servlet 3.0 注解配置:
在我们上面的 代码中, 如果 添加了一个 新的 Servlet , 那么 在 web.xml 配置文件中, 就要再 配置一次 路径, 如果 我们 有 几十, 成百个 Servlet , 那么 如果 这样配置 就显得 比较麻烦, 代码 也很 混乱, 也很多 . 解决方案 :
* Servlet 3.0 版本 的 好处:
* 支持 注解配置. 可以不需要 web.xml 配置文件 进行配置了.
步骤:
1. 创建 JavaEE 项目, 选择 Servlet 的版本 3.0 以上. (3.0 以上 的版本 都支持 注解 配置了. ), 可以 不创建 web.xml.
2. 定义一个 Servlet(Java类), 实现 Servlet 接口.
3. 复写方法.
4. 在 类上 使用 @WebServlet 注解, 进行配置.
@WebServlet("(资源路径)/demo2")
虚拟 目录是 项目的 访问方式: /day13_Servlet
这个 注解配置的 括号里 填的是 资源 路径: 映射 类(资源)的 路径.
不同的 JavaEE 版本 对应不同的 版本. JavaEE 6 以上 都支持 3.0 版本 .
创建的 时候 不勾选 web.xml. 这时 可以发现 目录结构中 WEB-INF / web.xml 这两个 文件夹都没有了.
将 @WebServlet 注解配置 写到 类里面, 这时 这个 注解 就在 这个 类里面, 它 是知道 类 在哪里的. 所以 不用配置 全类名 , 只需要 配置 (访问 这个 资源的 虚拟目录(路径)).
CTRL + N : idea 快捷键 , 查找 一个 类 或 其它 所有.
@WebServlet(urlPatterns = "/demo")
/day13_Servlet
http://localhost:8080/day13_Servlet/demo
urlPatterns [ ] = { }, 这里面可以配置 多个 路径. 我们这里 就配置 一个 路径 所以 可以 省略 大括号.
配置文件中 有一个 value(一般 value 都是最重要的) , 我们 就配置一个 属性 可以写成 @WebServlet(value = "/demo"), 又因为 value 是 最重要的, 可以不写(不写 它都有, 重要), 可以写成 @WebServlet("/demo")
*** 以后 就使用 这种 方式 进行配置. (方便 许多. )
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package javax.servlet.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebServlet {
String name() default "";
String[] value() default {};
String[] urlPatterns() default {};
int loadOnStartup() default -1;
WebInitParam[] initParams() default {};
boolean asyncSupported() default false;
String smallIcon() default "";
String largeIcon() default "";
String description() default "";
String displayName() default "";
}
log : 日志(信息).
## IDEA 与 Tomcat 相关配置.
1. IDEA 会为 每一个 tomcat 部署的 项目 单独建立一份 配置文件.
src 下的 Java文件 将来 被 编译成后, 会被放到 WEB-INF 目录下的 classes 目录下.
2. 工作 空间 项目 和 tomcat 部署的 web 项目(在 out 目录下. ). 与 IDEA 目录 结构 对应.
* tomcat 真正 访问的是 "tomcat 部署的 web 项目", "tomcat 部署的 web 项目" 对应着 "工作空间 项目" 的 web 目录下的 所有资源....
out / artifacts / day13_tomcat_war_exploded. war 包.
* WEB-INF 目录下的 资源 不能被浏览器 直接访问.
* 以后 不要将 资源 (静态资源...) 放到 WEB-INF 目录下. 以后 有其它 技术可以访问到 里面的 资源, 现在 先 不要 放在 这个 (WEB-INF)目录下.
3. Tomcat 的 断点调试.
以 "小虫子(debug) 的 方式 来启动 就是 以 调试的 方式来启动 这个 服务器, 并且 部署 这个项目. (在 类文件中 打断点. )"
Variables : 查看变量的 变化 情况.
* 查看控制台的 log: Using CATALINA_BASE: "C:\Users\闲客\.IntelliJIdea2019.2\system\tomcat\_Project01"
在里面的 conf(配置) 文件夹下 有很多的 配置文件, 其中的 serve.xml 中 我们 之前 修改 端口号, 就是在 其中修改, 现 在 IDEA 开发工具 的 Tomcat 中 修改 这个 项目的 端口号, 重新 启动 Tomcat , 那么 这里的 配置文件 随之 更改.
Catalina 文件夹 / localhost / .xml 就是 配置的 虚拟 目录.
docBase: 其中存放的 就是 我们的 项目 存放的 路径.
这就是我们 之前 的 第三种 部署项目的 方式.
动态 项目的 目录结构 :
WEB-INF / web.xml(配置文件) classes / 字节码 文件 . class 与 IDEA 目录 结构 对应.