【学习笔记】手写 Tomcat 七

目录

一、优化 Dao 

1. 设置 UserDaoImpl 为单例模式

2. 创建 Dao 工厂

3. 在 Service 层获取 UserDao 的实例

二、优化 Service

1. 设置 UserServiceImpl 为单例模式

2. 创建 Service 工厂

3. 在 Servlet 层获取 Service 实现类的对象

三、优化 Servlet

1. 使用配置文件

1. 创建配置文件

2. 创建工具类

3. 调用工具类获取对象

测试

2. 使用注解的方式

1. 创建自定义注解

2. 使用注解

3. 创建工具类

4. 获取对象

测试

四、作业

1. 绘制架构图

2. 了解 NIO


一、优化 Dao 

1. 现在在 Service 层,调用Dao层的实现类都要 new 一下,这样就会创建很多对象,比较占内存,比如 Service 层的其他实现类也会调用 UserDao,那么只需要创建一次 UserDao 的对象就行了

使用单例模式

2. 既然 Service 层的很多方法可能也会调用UserDao,如果以后需要更换 UserDao的实现类,那么所有调用 UserDao 的地方都需要修改一下,这样比较麻烦

使用工厂模式获取 UserDao 的对象,如果要修改,只需要在工厂类修改即可

1. 设置 UserDaoImpl 为单例模式

2. 创建 Dao 工厂

用于获取 Dao 的不同实例

3. 在 Service 层获取 UserDao 的实例

二、优化 Service

和 Dao 层同理,在 Servlet 层也多次创建了 UserService 的实现类,比如登录和修改密码都用到了UserService

1. 设置 UserServiceImpl 为单例模式

2. 创建 Service 工厂

package com.shao.Service;import com.shao.Service.Impl.UserServiceImpl;public class ServiceFactory {public static UserService getUserService() {return UserServiceImpl.getInstance();}
}

3. 在 Servlet 层获取 Service 实现类的对象

三、优化 Servlet

现在的情况是当 Tomcat 接收一个请求后,会先判断是请求的静态资源还是动态资源,如果是动态资源,还要继续判断请求的是哪个功能,然后调用相应的 Servlet 执行

这样有些缺点,当功能很多时,一个个判断请求的是哪个功能,效率不高,而且代码不够优雅,并且来一个请求就会创建一下 Servlet 对象,比较消耗资源,那如何解决呢?

解决方案是:我们先把所有的 Servlet 对象创建好,然后放到一个容器(集合)里,当有请求时,取出对应的 Servlet 对象执行。这是不是很熟悉的感觉?池化思想

那么问题来了,系统怎么知道哪些 Servlet 需要创建对象?

1. 使用配置文件

把要创建的 Servlet 的全类名放到配置文件,然后读取配置文件,通过反射技术创建对象

1. 创建配置文件

2. 创建工具类

package com.shao.Utils;import com.shao.Servlet.BaseServlet;import java.io.File;
import java.io.FileInputStream;
import java.util.HashMap;
import java.util.Properties;
import java.util.Set;public class ServletUtil {// 获取当前系统分隔符final static String FENGEFU = File.separator;// 存放 Servlet 对象static HashMap<String, BaseServlet> map = new HashMap<>();// 读取配置文件的内容static Properties properties = new Properties();static {try {properties.load(new FileInputStream("config" + FENGEFU + "Servlet.properties"));// 把 Key 放到集合中Set<Object> keySet = properties.keySet();for (Object key : keySet) {String value = properties.getProperty(key.toString());// 通过全类名获取 Class 对象,Class 对象记录了这个类的全部信息Class<?> aClass = Class.forName(value);/**   底层原理:*   1. 调用构造器,通过 Class 对象找到对应类型的无参构造器*   2. 实例化对象:使用构造器创建一个新的对象实例*   3. 返回实例* */BaseServlet baseServlet = (BaseServlet) aClass.newInstance();// 添加到 map 集合map.put(key.toString(), baseServlet);}} catch (Exception e) {e.printStackTrace();}}// 对外提供一个接口,获取集合中 key 对应的 value ,value 是 Servlet 对象public static BaseServlet getServletClass(String key) {return map.get(key);}}

3. 调用工具类获取对象

在响应类调用 ServletUtil 获取Servlet 实例

package com.shao.net;import com.alibaba.fastjson2.JSON;
import com.shao.Servlet.BaseServlet;
import com.shao.Servlet.ChangePasswordServlet;
import com.shao.Servlet.LoginServlet;
import com.shao.Utils.DBConnectUtil;
import com.shao.Utils.ServletUtil;
import com.shao.Utils.responseDTO;import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.sql.*;public class HttpResponse {/*** 输出流*/private OutputStream os;/*** 解析请求信息的对象*/private HttpRequest httpRequest;public HttpResponse(OutputStream os, HttpRequest httpRequest) {this.os = os;this.httpRequest = httpRequest;}public void response(String filePath) {//判断请求的是否为静态文件if (StaticResourceHandler.isLikelyStaticResource(httpRequest.getRequestModule())) {// 获取静态资源一般是 GET 请求方法if (httpRequest.getRequestMethod().equals("GET")) {// 响应静态资源responseStaticResource(filePath);}} else {// 处理动态请求System.out.println("请求动态资源");// 获取 Servlet 对象,参数是请求的模块名BaseServlet servlet = ServletUtil.getServletClass(httpRequest.getRequestModule());// 如果没有找到对应的 Servlet ,返回 404if (servlet == null) {responseStaticResource("webs/pages/not_Found404.html");return;}// 调用 service 方法servlet.service(httpRequest, this);//            if (httpRequest.getRequestModule().equals("/doLogin")) {
//
//                // 创建 登录的 Servlet 对象
//                LoginServlet loginServlet = new LoginServlet();
//
//                // 调用 service 方法,响应数据也封装在 servlet 里
//                loginServlet.service(httpRequest, this);
//
//
//            } else if ("/ChangePassword".equals(httpRequest.getRequestModule())) {
//
//                ChangePasswordServlet servlet = new ChangePasswordServlet();
//
//                servlet.service(httpRequest, this);
//            } else if ("/test".equals(httpRequest.getRequestModule())) {
//                send(JSON.toJSONBytes(new responseDTO(200, "ok", "test")));
//            }}}/*** 响应静态资源*/private void responseStaticResource(String filePath) {// 读取文件byte[] fileContents = StaticResourceHandler.getFileContents(filePath);// 判断文件是否存在,不存在则返回 404 的页面if (fileContents == null) {try {FileInputStream fis = new FileInputStream("webs/pages/not_Found404.html");fileContents = new byte[fis.available()];fis.read(fileContents);fis.close();} catch (Exception e) {e.printStackTrace();}}// 响应协议String protocol = httpRequest.getRequestProtocol();// 文件媒体类型String fileMimeType = StaticResourceHandler.getFileMimeType(filePath);try {os.write((protocol + " 200 OK\r\n").getBytes());os.write(("Content-Type: " + fileMimeType + "\r\n").getBytes());os.write(("Content-Length: " + fileContents.length + "\r\n").getBytes());os.write("\r\n".getBytes());os.write(fileContents);os.flush();System.out.println("响应成功");os.close();} catch (IOException e) {e.printStackTrace();}}public void send(byte[] content) {// 获取请求协议String protocol = httpRequest.getRequestProtocol();try {os.write((protocol + " 200 OK\r\n").getBytes());os.write(("Content-Type: " + "text/html;charset=utf-8" + "\r\n").getBytes());os.write(("Content-Length: " + content.length + "\r\n").getBytes());os.write("\r\n".getBytes());os.write(content);os.flush();System.out.println("响应成功");os.close();} catch (IOException e) {e.printStackTrace();}}
}

测试

2. 使用注解的方式

在需要创建的 Servlet 的类名上加上自定义注解,然后通过反射技术创建对象

1. 创建自定义注解

package com.shao.Annotation;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)
public @interface MyServlet {String value();
}

2. 使用注解

3. 创建工具类

package com.shao.Utils;import com.shao.Annotation.MyServlet;
import com.shao.Servlet.BaseServlet;import java.io.File;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashMap;public class ServletByAnnoUtil {// 存放 Servlet 对象private static HashMap<String, BaseServlet> map = new HashMap<>();// 要扫描包的路径private static String PackagePath = "com.shao.Servlet";static {// 获取类加载器ClassLoader classLoader = ServletByAnnoUtil.class.getClassLoader();// 获取包的完整路径URL resource = classLoader.getResource(PackagePath.replace(".", "/"));if (resource == null) {throw new RuntimeException("Package path not found:" + PackagePath);}try {// 创建目录对象File packageDir = new File(resource.toURI());// 获取目录下所有文件File[] files = packageDir.listFiles();/**   1. 判断文件是否为 .class 文件*   2. 获取文件名,去掉 .class 后缀*   3. 包路径 + 文件名,拼接成全类名*   4. 获取 Class 对象*   5. 判断 Class 对象是否有 MyServlet 注解*   6. 如果有,判断是否 BaseServlet 类,或者继承 BaseServlet*   7. 创建对象,获取注解的值,存放到 map 中** */for (File file : files) {if (file.getName().endsWith(".class")) {// 获取全类名String className = PackagePath + "." + file.getName().substring(0, file.getName().lastIndexOf("."));// 获取 Class 对象Class<?> aClass = Class.forName(className);// 判断是否有 MyServlet 注解if (aClass.isAnnotationPresent(MyServlet.class)) {// 判断是否继承 BaseServletif (BaseServlet.class.isAssignableFrom(aClass)) {// 创建对象BaseServlet servlet = (BaseServlet) aClass.newInstance();// 获取注解的值MyServlet annotation = aClass.getAnnotation(MyServlet.class);map.put(annotation.value(), servlet);}}}}} catch (URISyntaxException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {throw new RuntimeException(e);}}// 对外提供一个接口,获取 Servlet 对象public static BaseServlet getServletClass(String key) {return map.get(key);}
}

4. 获取对象

测试

四、作业

1. 绘制架构图

2. 了解 NIO

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Leetcode面试经典150题-322.零钱兑换

给你一个整数数组 coins &#xff0c;表示不同面额的硬币&#xff1b;以及一个整数 amount &#xff0c;表示总金额。 计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额&#xff0c;返回 -1 。 你可以认为每种硬币的数量是无限的。 示…

【无人机设计与控制】Multi-UAV|多无人机多场景路径规划算法MATLAB

摘要 本研究探讨了多无人机路径规划问题&#xff0c;提出了三种不同算法的对比分析&#xff0c;包括粒子群优化&#xff08;PSO&#xff09;、灰狼优化&#xff08;GWO&#xff09;和鲸鱼优化算法&#xff08;WOA&#xff09;。利用MATLAB实现了多场景仿真实验&#xff0c;验证…

C++那些事之内存优化

C那些事之内存优化 通常程序运行时内存是一个比较大的问题&#xff0c;如何减少内存占用和提升访问速度是至关重要。为了解决这些问题&#xff0c;C20 引入了 no_unique_address 特性&#xff0c;并结合空基类优化&#xff08;EBO, Empty Base Optimization&#xff09;&#x…

组合优化与凸优化 学习笔记5 对偶拉格朗日函数

有的时候约束条件有点难搞&#xff0c;我们可以把它放到目标函数里面。 记得之前凸函数的时候的结论吗&#xff1f;一大堆函数&#xff0c;每一段都取最大的&#xff0c;最后会得到一个凸函数。同理&#xff0c;每一段都取最小的&#xff0c;得到的是一个凹函数。就这样&#x…

【Golang】Go语言字符串处理库--strings

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

数通 1

通信&#xff1a;需要介质才能通信电话离信号塔&#xff08;基站&#xff09;越远&#xff0c;信号越弱。信号在基站之间传递。你离路由器越远&#xff0c;信号越差。一个意思 比如想传一张图片&#xff0c;这张图片就是数据载荷 网关&#xff0c;分割两个网络。路由器可以是网…

宠物医院微信小程序源码

文章目录 前言研究背景研究内容一、主要技术&#xff1f;二、项目内容1.整体介绍&#xff08;示范&#xff09;2.系统分析3.数据表信息4.运行截图5.部分代码介绍 总结 前言 随着当代社会科技的迅速发展&#xff0c;计算机网络时代正式拉来帷幕&#xff0c;它颠覆性的影响着社会…

新版pycharm如何导入自定义环境

我们新的版本的pycharm的ui更改了&#xff0c;但是我不会导入新的环境了 我们先点击右上角的add interpreter 然后点击添加本地编译器 先导入这个bat文件 再点击load 我们就可以选择我们需要的环境了

SpringBoot3脚手架

MySpringBootAPI SpringBoot3脚手架&#xff0c;基于SpringBoot3DruidPgSQLMyBatisPlus13FastJSON2Lombok&#xff0c;启动web容器为Undertow(非默认tomcat)&#xff0c;其他的请自行添加和配置。 <java.version>17</java.version> <springboot.version>3.3…

android SELinux权限适配

抓log方法&#xff0c; setenforce 0, 如果不先将selinux设置为permission mode&#xff0c;会导致一个问题。 程序运行的时候遇到权限策略限制&#xff08;假设 sepolicy 1&#xff09;&#xff0c;程序运行失败。添加权限&#xff08;sepolicy 1&#xff09;&#xff0c;然后…

Mysql 删除表的所有数据

在 MySQL 中&#xff0c;如果你想要删除一个表中的所有数据&#xff0c;可以使用 TRUNCATE TABLE 命令或者 DELETE 语句。下面是两种方法的对比以及如何使用它们&#xff1a; 使用 TRUNCATE TABLE TRUNCATE TABLE 是一个非常快速的方法来删除表中的所有记录&#xff0c;并且它…

工作日志:el-table在无数据情况下,出现横向滚动条。

1、遇到一个警告。 原因&#xff1a;中的组件不能呈现动画的非元素根节点。 也就是说&#xff0c;Transition包裹的必须是一个单根的组件。 2、el-table在无数据情况下&#xff0c;出现横向滚动条&#xff0c;大概跟边框的设置有关系。 开始排查。 给.el-scrollbar加了一个…

电影《749局》酷燃首映 苗苗神秘感大片释出氛围感拉满

2024 年 9 月 30 日&#xff0c;电影《749 局》在北京举办首映礼&#xff0c;导演陆川携主创王俊凯、苗苗、郑恺、任敏、李晨、杨皓宇出席&#xff0c;演员苗苗在片中饰演 749 局成员夏婳&#xff0c;这个角色天赋异禀&#xff0c;拥有特殊异能&#xff0c;为影片增添一抹神秘色…

如何微信多开

目录 1.找到微信在文件夹的位置 2.建文本&#xff0c;放代码 3.保存文本&#xff0c;更改后缀 4.使用 1.找到微信在文件夹的位置 1.首先找到你微信所在的文件夹&#xff0c;有桌面图标的点击右键属性&#xff0c;找到微信快捷启动exe程序。 2.建文本&#xff0c;放代码 2.…

WebAssembly 为什么能提升性能,怎么使用它 ?

文章目录 简介&#xff1a;起源&#xff1a;前端性能提升历史JIT&#xff08;Just-In-Time&#xff09;编译器(即时编译) 为什么需要WebAssembly&#xff1a;WebAssembly能做什么&#xff1a;经常说WASM的性能高&#xff0c;为什么高&#xff1f;&#xff1f;使用方法:Emscript…

使用AOP处理参数

说明&#xff1a;在一些时候&#xff0c;我们需要在接口介绍到参数前处理参数&#xff0c;像参数校验、参数转换等&#xff0c;本文介绍如何使用AOP来实现此需求。 场景 需求&#xff1a;有一批开放给第三方调用的接口&#xff0c;之前传递的都是用户表的ID&#xff0c;现在需…

“改善就医感受 提升患者体验”经验交流首场活动在呼市顺利举行

2024年9月26日至27日&#xff0c;以“医疗机构高质量发展 促进医改全面深化”为主题的“改善就医感受 提升患者体验”经验交流系列活动&#xff08;以下简称&#xff1a;系列活动&#xff09;首场活动在内蒙古呼和浩特顺利举行。 活动现场 患者体验&#xff0c;并不等同于患者…

CleanMyMac X v4.12.1 中文破解版 Mac优化清理工具

在数字时代&#xff0c;我们的Mac设备承载着越来越多的重要信息和日常任务。然而&#xff0c;随着时间的推移&#xff0c;这些设备可能会变得缓慢、混乱&#xff0c;甚至充满不必要的文件。这就是CleanMyMac X发挥作用的地方。 CleanMyMac X是一款功能强大的Mac优化工具&#…

获取 Jupyter Notebook IPython kernel 在电脑中的目录位置

获取 Jupyter Notebook IPython kernel 在电脑中的目录位置 正文 正文 在 VS code 的 terminal 中或者 Windows 的命令行中使用如下代码即可。 ipython locate运行后得到如下结果&#xff1a; 如图所示&#xff0c;我们获取到了 ipython 的位置。 如果大家觉得有用&#xf…

自动驾驶汽车横向控制方法研究综述

【摘要】 为实现精确、稳定的横向控制&#xff0c;提高车辆自主行驶的安全性和保障乘坐舒适性&#xff0c;综述了近年来自动驾驶汽车横向控制方法的最新进展&#xff0c;包括经典控制方法和基于深度学习的方法&#xff0c;讨论了各类方法的性能特点及在应用中的优缺点&#xff…