【学习笔记】手写 Tomcat 五

手写一个Tomcat (参考了公众号:java架构沉思录中的文章:教你写一个迷你版的toncat 原文:https://www.jianshu.com/p/dcelee01fb90) 作为一个java学习的起步者,对tomcat的认识还是有很多的欠缺,在无意中发现了这篇文章,便在自己的环境下尝试搭建,收获良多: 分以下几个步骤: (1)提供Socket服务 (2)进行请求的转发 (3)把请求和响应封装成request/... 阅读详情

目录

一、优化 Servlet

创建一个抽象类

继承抽象类

二、三层架构 

业务逻辑层

数据访问层

1. 在 Dao 层操作数据库

2. 调用 Dao 层,实现业务逻辑功能

3. 调用 Service 层,响应数据

测试

三、数据库连接池

1. 手写数据库连接池

2. 创建数据库连接池的类

3. 初始化连接池

4. 在 Dao 层获取数据库连接

5. 归还数据库连接

作业

1. 3w1h的方式,了解单例模式

2. 了解其他连接池


一、优化 Servlet

昨天,我们把响应动态资源的功能放到了 Servlet,一个 Servlet 就是一个功能

当 Servlet 多了之后,我们会发现,每个 Servlet 里都有 service 方法,那有什么方法可以简化呢?

这里就可以使用 Java 的三大特性之一 继承

创建一个抽象类

定义普通的 service 方法,和 doGet , doPost 抽象方法

继承抽象类

在每个 Servlet 中继承这个抽象类,然后就可以删除 service 方法了

二、三层架构 

我们把功能都写在了 Servlet,这样有几个缺点,一是不够低耦合 高内聚,二是不方便协同开发等

我们可以使用三层架构来解决这个问题

三层架构是一种设计思想,分为表示层,业务逻辑层和数据访问层

表示层 Servlet:负责处理用户的请求和响应用户需要的数据

业务逻辑层 Service:负责业务上逻辑的处理,也是表示层和数据层之间的桥梁,

数据访问层 Dao:操作数据库,进行增删改查,并将结果传给业务逻辑层

三层架构区分层次的目的是为了 “高内聚,低耦合”。开发人员分工更明确

业务逻辑层

创建 UserService 接口,用于专门处理用户相关的业务逻辑,比如用户登录,注册,修改密码等

创建接口的实现类,在实现类里实现业务相关逻辑

为什么要创建接口,再创建实现类去实现接口呢?直接创建类,在类里实现业务逻辑不行吗?

当然可以,不过面向接口有很多优点。比如解耦,当实现类需要改变,不会影响 Servlet 层。还有规范化等优点

数据访问层

创建 UserDao 接口,并创建实现类,和业务逻辑层同理

在接口定义抽象方法

1. 在 Dao 层操作数据库

在实现类实现接口,并把 Servlet 层的关于数据库操作的代码放到实现类里

package com.shao.Dao.Impl;

import com.shao.Dao.UserDao;
import com.shao.Utils.DBConnectUtil;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class UserDaoImpl implements UserDao {

    @Override
    public int Login(String account, String password) {

        Connection connection = null;
        PreparedStatement pstmt = null;
        ResultSet resultSet = null;
        int result = 0;

        try {

            // 3. 获取数据库连接
            connection = DBConnectUtil.getConnection();

            // 4. 获取可执行对象
            String SQL = "select count(*) from train.users where account = ? and password = ?";
            pstmt = connection.prepareStatement(SQL);

            // 设置占位符的值
            pstmt.setString(1, account);
            pstmt.setString(2, password);

            // 5. 执行sql语句,获取结果集
            resultSet = pstmt.executeQuery();

            // 6. 结果处理
            if (resultSet.next() && resultSet.getInt(1) > 0) {

                // 表示可以查询到数据
                result = 1;
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {

            // 7. 释放资源
            DBConnectUtil.releaseSource(connection, pstmt, resultSet);
        }

        // 返回结果给业务逻辑层
        return result;
    }
}

2. 调用 Dao 层,实现业务逻辑功能

在 Service 层调用 Dao 层,并实现业务逻辑功能

package com.shao.Service.Impl;

import com.shao.Dao.Impl.UserDaoImpl;
import com.shao.Dao.UserDao;
import com.shao.Service.UserService;
import com.shao.Utils.responseDTO;

public class UserServiceImpl implements UserService {

    // 创建一个UserDao的实现类对象
    private UserDao userDao = new UserDaoImpl();
    
    @Override
    public responseDTO Login(String account, String password) {

        // 调用UserDao的Login方法
        int login = userDao.Login(account, password);
        
        // 判断是否登录成功
        if (login == 1) {
            return new responseDTO(200, null, "登录成功");
        } else {
            return new responseDTO(201, null, "账号或密码错误");
        }
    }
}

3. 调用 Service 层,响应数据

在 Servlet 层调用 Service 层,然后把业务逻辑层返回的数据响应到客户端

package com.shao.Servlet;

import com.alibaba.fastjson2.JSON;
import com.shao.Service.Impl.UserServiceImpl;
import com.shao.Service.UserService;
import com.shao.Utils.responseDTO;
import com.shao.net.HttpRequest;
import com.shao.net.HttpResponse;


public class LoginServlet extends BaseServlet {
    responseDTO responseDTO = null;

    public void doGet(HttpRequest request, HttpResponse response) {

        // 获取请求参数
        String account = request.getRequestBodyParams().get("account");
        String pwd = request.getRequestBodyParams().get("password");

        // 调用 Service 层的Login方法
        UserService userService = new UserServiceImpl();
        responseDTO = userService.Login(account, pwd);

        // 响应数据
        response.send(JSON.toJSONBytes(responseDTO));
    }

    public void doPost(HttpRequest request, HttpResponse response) {
        responseDTO = new responseDTO(400, null, "不支持POST提交方法");
        response.send(JSON.toJSONBytes(responseDTO));
    }
}

测试

三、数据库连接池

在测试的时候,我们可能会发现,第一次登录的时候,数据响应会比较慢,第二次之后就比较快了

这是因为第一次登录需要与数据库进行连接,第二次访问时,数据库已经准备好了,所以比较快

而且,当用户很多时,发起一次请求就需要建立一个数据库连接,不用了就断开连接,这样比较消耗资源,也比较耗时

那如何解决这个问题呢?

解决方案是使用数据库连接池,在系统空闲的时候,创建好数据库连接,当用户发起请求后就从连接池取出一条连接使用,当用完了再把连接放到连接池中,这样就节约了资源,也提升了效率

数据库连接池可以使用市面上的,比如Druid,Apache DBCP 等

1. 手写数据库连接池

这里我们手写一个简单的数据库连接池

在设计数据库连接池之前,我们需要确定,这个连接池一个就可以了,所以连接池的类就只能有一个实例(对象),这就可以用到单例的设计模式。使用哪种方式创建单例模式,如果使用饿汉式,需要提前加载好连接池

2. 创建数据库连接池的类

package com.shao.Utils;

import java.sql.Connection;
import java.util.LinkedList;

public class DBConnectPool {

    // 定义一个双向链表,存放连接
    private static final LinkedList<Connection> connectionPool = new LinkedList<>();

    // 连接池最大连接数
    private static final int maxSize = 10;


    // 定义一个成员变量,存储单例对象
    private static DBConnectPool dbConPool;

    // 静态代码块,在类加载时,就会执行代码块,且只执行一次
    // 调用工具类获取连接,然后添加到连接池中
    static {
        for (int i = 0; i < maxSize; i++) {
            Connection connection = DBConnectUtil.getConnection();
            if (connection != null) {
                connectionPool.add(connection);
            }
        }
    }

    // 私有构造方法,防止外部实例化
    private DBConnectPool() {
    }

    // 对外提供一个接口,用于获取DBConnectPool对象
    public static DBConnectPool getInstance() {
        synchronized (DBConnectPool.class) {
            if (dbConPool == null) {
                dbConPool = new DBConnectPool();
            }
            return dbConPool;
        }
    }

    // 获取连接
    public Connection getConnection() {
        // 从连接池删除一个连接,然后把连接返回
        // 以同步的方法获取连接,保证线程安全
        synchronized (DBConnectPool.class) {
            Connection poll = connectionPool.poll();
            return poll;
        }
    }

    // 释放连接
    public void releaseConnection(Connection connection) {
        if (connection == null) {
            return;
        }
        //把连接放回连接池
        synchronized (DBConnectPool.class) {
            connectionPool.add(connection);
        }
    }
}

3. 初始化连接池

用饿汉式创建连接池,所以需要在启动 Tomcat 的时候就加载好连接池

4. 在 Dao 层获取数据库连接

5. 归还数据库连接

在数据库连接工具类的释放资源的方法中可以删掉释放数据库连接的参数,改为使用连接池的归还连接的方法

作业

1. 3w1h的方式,了解单例模式

2. 了解其他连接池

优快云学习笔记之一 我的学习笔记,不断更新中。 愁死我了,要我写20字。真难凑合 立即下载

相关推荐

Stata:手动安装ivreghdfe包的完整指南与常见问题解决

本文提供了Stata中手动安装ivreghdfe包的完整指南,包括准备工作、详细安装步骤及常见问题解决方案。ivreghdfe作为处理高维固定效应模型的强大工具,依赖ftools、reghdfe和ivreg2三个核心组件,手动安装可避免版本冲突问题。文章还分享了进阶使用技巧,如并行计算加速和保存固定效应估计值,助力用户高效完成工具变量回归分析。

weixin_29251131的博客 929

csdn笔记

1

simple1134的博客 583

DNA pull-down技术避坑指南:从探针设计到质谱验证的完整实验方案

本文提供了一份详尽的DNA pull-down技术实战避坑指南,涵盖从探针设计、生物素标记、磁珠选择与预处理,到结合洗脱优化及下游质谱验证或Western Blot验证的全流程。重点解析了如何通过精细操作降低非特异性结合、提高实验特异性与重复性,并对比了质谱与WB两种验证路径的适用场景,旨在帮助研究者构建稳健可靠的DNA-蛋白质互作研究体系。

weixin_29274337的博客 495

还是在csdn做笔记吧

之前因为为了方便一直在百度空间做笔记,但是,百度空间竟然不运营了。   后来,提升一下逼格,加之lofter出了支持百度空间导入lofter的功能,就都搬去lofter了。可是,轻博客也太轻了吧,代码插入排版什么的我是没找到。   看来做笔记还是csdn靠谱点,毕竟也算有针对性吧

wyude的专栏 680

压电传感器信号放大难题?用运放设计电荷放大器的5个关键步骤

本文详细解析了压电传感器信号放大难题,并提供了用运放设计电荷放大器的5个关键步骤。从电压放大到电荷放大的范式转换,到运放选型、反馈网络设计、PCB布局及频响特性验证,帮助工程师解决工业自动化中的信号衰减问题,提升测量精度和稳定性。

weixin_27303545的博客 449

同花顺 python量化交易_开启量化第一步!同花顺iFinD数据接口免费版简易操作教程...

来源:雪球App,作者: 同花顺-iFinD,(https://xueqiu.com/6706494343/141951051)金融市场波动频繁,投资往往会夹杂非理性的情绪。而量化交易,旨在以先进的数学模型替代人为的主观判断,利用计算机技术从庞大的历史数据中海选能带来超额收益的多种“大概率”事件以制定策略,辅助投资者进行理性投资。不过计算机分析存在一定的技术门槛,有没有简单易学的量化交易方式,能够...

weixin_35911805的博客 2万+

读书笔记

一面向对象的主要特征:1.抽象:将一类对象的共同特征总结出来的构造的过程,包括数据抽象和行为抽象两方面,抽象只关注对象有哪些属性和行为。2.封装:将数据和操作数据的方法绑定起来,对数据的访问只能通过定义的接口,类中的方法就是对现实世界的一种封装。3.继承:从已有类得到信息创建新类的过程,提供继承信息的类被称为父类,得到继承信息的类为子类。4.多态性:同样的对象引用调用同样的方法做不同的事情。多态性...

panyaguang的博客 245

深入解析ADC采样电容:从充电误差到LSB精度的关键设计

本文深入解析了ADC采样电容在模数转换中的核心作用,重点探讨了充电时间常数与采样误差的博弈关系。通过推导最小采样时间公式,揭示了精度、速度、源阻抗与内部电容之间的制约关系,并提供了从理论计算到外部驱动电路设计的实战指南,是确保ADC达到LSB精度的关键。

android的专栏 1103

开始学习点优快云东西

开始学习点优快云东西,争取每周来记一次学习内容和知识和技巧经验等。

zhongguogansu的博客 83

写一个b站爬虫(思路)

part 0 安装 scrapy, requests part 1 信息获取 打开番剧索引链接(https://www.bilibili.com/anime/index/) F12控制台,选中NETWORK,来到xhr文件,我们可以找到了存放番剧json的地方

kou的博客 485

ShengBTE热导计算:利用ShengBTE计算热导显示NAN的原因是什么?算出的热导不随平均声子自由程变化

🏆本文收录于 《全栈 Bug 调优(实战版)》 专栏。专栏聚焦真实项目中的各类疑难 Bug,从成因剖析 → 排查路径 → 解决方案 → 预防优化全链路拆解,形成一套可复用、可沉淀的实战知识体系。无论你是初入职场的开发者,还是负责复杂项目的资深工程师,都可以在这里构建一套属于自己的「问题诊断与性能调优」方法论,助你稳步进阶、放大技术价值 。

**My Coding Family** 964

Java学习笔记

未完待续

m0_51060495的博客 1986

【毕设救星】从0到1打造YOLOv8货架商品检测与可视化系统,让你的毕设脱颖而出

本文介绍了一个基于YOLOv8的货架商品检测系统毕设项目。系统采用YOLOv8模型进行商品检测,包含环境搭建、数据集准备、模型训练与验证等完整流程,并开发了可视化UI界面。项目聚焦智能零售应用场景,技术栈完整且易于实现,适合作为计算机视觉方向的毕业设计。文章详细指导了从数据标注、模型训练到界面开发的全过程,提供代码示例和实用建议,帮助学生快速完成毕设并提升答辩表现。

LXY_LOVE36的博客 103

手写Tomcat

tomcat提供的服务: 第一:提供Socket服务 第二:进行请求的分发 第三:需要把请求和响应封装成request/response

书生的博客 4098

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

自己手写tomcat项目

在Servlet(接口中)有:1.init():初始化servlet2.getServletConfig():获取当前servlet的配置信息3.service():服务器(在HttpServlet中实现,目的是为了更好的匹配http的请求方式)4.getServletInfo():获取servlet当前运行过程中的信息5.destroy():销毁,回收内存在I/O中应包含:1.请求头(f12+网络) 2.请求方式(get/post) 3.请求内容。

2302_79585857的博客 1799

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

【学习笔记】手写 Tomcat -- 预备知识

I 是 Input,O 是Output,也就是输入输出流。当我们操作数据时,以内存为基准,把数据读取到内存中是输入,把数据从内存写入到硬盘是输出。

LearnTech_123的博客 1645

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

【学习笔记】手写 Tomcat 六

昨天使用了数据库连接池,我们了解了连接池的优点,那么也可以使用线程池来管理线程,java自带的线程池的参数有 核心线程数,最大线程数,线程活跃时间,时间单位,任务队列,线程工厂,拒绝策略。为了学习了解线程池,我们先手写一个简单的线程池,只需要做到核心线程可重复利用就行。

LearnTech_123的博客 1763

18_1手写Tomcat学习笔记

tomcat学习笔记 文章目录1 tomcat简介1.1 web服务器1.2 tomcat服务器1.2.1 下载1.2.2 安装1.2.3 配置1.2.4 tomcat目录结构1.2.5 如何去访问一个web应用的某个文件1.2.6 在web服务器中安装web应用1.2.7 配置虚拟目录1.2.8 虚拟主机1.3 浏览器访问web站点原理2 手写tomcat_静态资源3 手写tomcat_动态资源3.1 tomcat工作原理3.2 http get请求格式3.2 http post请...

tangguanlin2008的博客 3741

手写简易Tomcat

通过手写tomcat对java中的网络通信有了更进一步的了解

Java新生代 1411

【学习笔记】手写 Tomcat 二

在昨天的基础上,再进一步优化,能够响应HTML文件,图片等静态资源。

LearnTech_123的博客 1485

从零开始手写Tomcat,一文彻底搞懂Tomcat运行流程(附源码)

一:理论铺垫 tomcat的功能是什么? tomcat是java的一个中间件,浏览器发出HTTP请求后经过tomcat中间件,转发到目的服务器,目的服务器返回响应消息,通过tomcat返回给浏览器。tomcat的使用很简单,但是作为合格的程序员,光会用可不行,接下来就通过手写一个tomcat彻底搞懂tomcat。 在手写Tomcat之前,首先重温一下http和servlet,http协议...

Java鱼仔的博客 7766

手写Tomcat框架

模型核心逻辑并发能力复杂度BIO一请求一线程,全程阻塞低简单NIO线程 + Selector 管多连接中高中等AIO异步通知,线程不等待高复杂2.扫描包的类用的是一个工具类进行实现的2.1首先 进行遍历获取类信息2.2通过反射机制,从目标类(clazz)中提取它上面标注的@WebServlet注解对象2.3这里获取类的无参构造方法 ---创建新的对象并强转向上转型为。

2302_80192044的博客 978
上一篇: 【学习笔记】手写 Tomcat 四
下一篇: 【学习笔记】手写 Tomcat 六
LearnTech_123
博客等级 码龄3年 445粉丝 31原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值