【学习笔记】手写 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字。真难凑合 立即下载

相关推荐

Optisystem软件与Matlab软件的联合数据读取

目录 Matlab软件程序编写 Optisystem软件的连接与设置 数据读取结果 Matlab软件程序编写 利用Matlab软件按照下图编写程序,保存为getdata.m文件。 OutputPort1 =InputPort1; fileID=fopen('OSAdata.txt','wt'); fprintf(fileID,'%f\n',OutputPort1.Sampled.Signal); fclose(fileID); Optisystem软件的连接与设置 (以基于线性插值法

Vivian_Chen_的博客 4854

csdn笔记

1

simple1134的博客 583

FMCW毫米波雷达原理一

1、简介 毫米波雷达的优点是角分辨率高、频带宽因而有利于采用脉冲压缩技术、多普勒颇移大和系统的体积小。目前笔者接触到的有24G毫米波雷达和77G毫米波雷达。 24G毫米波雷达主要应用在交通领域的测距和车辆测速,在其他领域也有使用24G毫米波雷达。 77G毫米波雷达主要应用在无人驾驶,汽车周围的目标检测等领域。 在首次接触雷达时,一头雾水。搞不清一个chirp的时域图和频域图的关系、中频信号以及其他名词的基本概念。在TI培训官网上看到一些毫米波雷达原理的视频才豁然开朗。TI培训官网毫米波传感介绍 本文主要是通

擎天柱工坊 8145

还是在csdn做笔记吧

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

wyude的专栏 680

JS逆向-快手__NS_hxfalcon参数分析

现在快手H5接口都需要__NS_hxfalcon这个参数,这篇文章就是逆向这个参数

ckcookies的博客 4076

XDMA 驱动安装与性能测试全流程解析

本文详细解析了XDMA驱动的完整安装与性能测试流程。从环境准备、源码获取、编译安装到驱动加载与设备验证,逐步指导用户打通FPGA加速卡与主机间的高速数据通道。重点介绍了如何通过官方测试脚本进行功能验证与带宽性能测试,帮助用户评估XDMA驱动的实际传输效能,为AI推理、高频交易等低延迟高带宽应用奠定基础。

weixin_29216049的博客 525

读书笔记

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

panyaguang的博客 245

【DRAM存储器五十一】LPDDR5介绍--DFE与Pre-Emphasis

简述LPDDR5的DFE和预加重应用设置

highman110的博客 707

开始学习点优快云东西

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

zhongguogansu的博客 83

五十天精通硬件设计第6天-放大器知识及选型

运算放大器(Operational Amplifier,简称运放)是一种高增益的直流耦合差分放大器,广泛应用于信号处理、滤波、比较、积分、微分等电路中。

whm128的博客 596

8、多导睡眠图记录中基于级联自适应滤波器的脑电图信号噪声去除

本文提出了一种基于三级级联自适应滤波器的新型方法,用于去除多导睡眠图(PSG)记录中脑电图(EEG)信号的常见伪迹,包括50/60 Hz电源线干扰、心电图(ECG)和眼电图(EOG)伪迹。该方法采用最小均方(LMS)算法,通过分阶段滤波有效分离并衰减各类噪声,在保留EEG关键神经节律信息的同时显著提升信号质量。研究利用MIT-BIH数据库中的18份真实PSG记录进行验证,结果表明该方法具有无相位失真、实现简单、自适应能力强等优势,适用于睡眠研究及脑机接口等生物医学应用领域。

banana的博客 174

Java学习笔记

未完待续

m0_51060495的博客 1986

CADENCE 25.1打开元件库ERRORCannot perform the operation because of an exception.

摘要:解决CADENCE25.1打开元件库报错"ERRORCannotperformtheoperationbecauseofanexception"的方法:该错误通常由软件中文设置导致。解决方案为:进入Options→Preferences→MorePreferences,取消勾选两个本地语言选项后重启软件即可恢复正常。此方法简单有效,能快速解决因语言设置导致的元件库访问异常问题。(98字)

0 1019

手写Tomcat

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

书生的博客 4098

OV9734 DATASHEET,完整规格书

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

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

自己手写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

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

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

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

LearnTech_123的博客 1645

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

【学习笔记】手写 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、付费专栏及课程。

余额充值