tomcat原理模拟和tomcat优化

news2024/9/22 13:30:17

1、tomcat实现原理

servlet 没有主方法main,依赖tomcat才能运行,因为tomcat 有主方法main,由java编写

servlet中doGet和doPost方法属于非静态方法,只能依托new对象存在,tomcat无法new出来对象,因此tomcat无法事先知道他们的存在。而任何语言都可以通过类的所在的路径或目录获取类信息,去某个目录下遍历所有子文件,能够获取所有文件的路径信息。tomcat可以通过servlet注解,找到对应的类,servlet注解相当于给类加了标记。

Tomcat和Servlet的关系是,Tomcat是Servlet容器,负责处理客户端的请求并将请求传递给Servlet,然后将Servlet的响应返回给客户。Servlet是一种运行在支持Java语言的服务器上的组件。

静态页面请求资源时,tomcat拷贝Html页面发送给浏览器,浏览器对html进行解析,浏览器看到src/href自动发请求。Tomcat将Http请求文本接收并解析,然后封装成HttpServletRequest类型的request对象,所有的Http头数据可以通过request对象调用对应的方法查询到。Servlet要响应的信息封装为HttpServletResponse类型的response对象,通过设置response属性就可以控制要输出到浏览器的内容,然后将response交给Tomcat,Tomcat就会将其变成响应文本的格式发送给浏览器。

浏览器对请求的资源会在content-type中标记类型,然后以相同类型返回,如请求的是html页面,返回的就是html页面;请求的是css,返回的就是css。

Tomcat的工作方式是,当它启动时,会把所有的Servlet都加载到内存中。具体而言,就是前端页面需要写请求路径和请求方法,一般是通过js的ajax给前端传输请求,这些请求借助socket接收,然后socket将这些信息根据http协议对这些字符串进行解析,识别出请求路径和请求参数,根据每个servlet中的注解找出请求路径,再根据请求路径判断调用哪个servlet。找到对应的Servlet后,Tomcat会调用该Servlet的相应方法(doGet或doPost)来处理这个请求。Servlet会解析请求参数,可能会做一些处理,然后返回一个响应。Servlet返回的响应会通过Tomcat传回给前端。这可能是一个HTML页面,也可能是一些JSON数据,取决于你的Servlet是如何处理的。前端接收到响应后,浏览器会根据响应的内容进行渲染。如果响应是一个HTML页面,浏览器就会展示这个页面。如果响应是一些JSON数据,那么前端可能会根据这些数据进行一些更新或者其他的操作。

具体流程如下图所示:

2、tomcat优化 

2.1 tomcat存在的问题

①挑选servlet很慢,因为跟硬盘交互;

②反射也很慢,就是遍历内存,CPU运算一次是纳秒级,这些都是毫秒级

2.2 tomcat优化一

挑选servlet后反射获取注解信息这一步可以进行优化,将servlet及对应的注解类信息放入一个map中,之后每次请求就直接通过map中的信息对servlet及注解信息进行筛选,只需要O(1)的时间复杂度,时间缩短为微秒级,tomcat启动时就会进行这一步操作。map中的value值是一个集合体,包含servlet对象,doget方法对象,dopost方法对象。

2.3 tomcat优化二

方法的调用是拷贝这一份方法压入栈中去执行,没有必要每次都创建对象执行方法,很占用内存,因为在操作系统中最小的内存分配单位是4KB,不管对象实际大小多大,每次最小分配4KB,大于4KB则是分配4KB的倍数,内存占的多影响运行速度,因此可以在tomcat启动阶段只创建一个对象,没有必要每次发送请求都创建一个对象获取方法执行,然后tomcat每次请求通过这一个对象进行方法的调用。因此,也可以只保留一个doGet和doPost方法,一个对象被多线程共用,类的对象保留一个,方法的对象保留一个,静态方法的调用不需要依托对象,非静态方法的调用需要依托对象

3、tomcat实现代码

①Client


import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;

public class Client extends Thread {

    //定义一个Socket对象
    Socket socket = null;

    public Client(String host, int port) {
        try {
            //需要服务器的IP地址和端口号,才能获得正确的Socket对象
            socket = new Socket(host, port);
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
    @Override
    public void run() {
        //客户端一连接就可以写数据给服务器了
        new sendMessThread().start();
        super.run();
        try {
            // 读Sock里面的数据
            InputStream s = socket.getInputStream();
            byte[] buf = new byte[4096];
            int len = 0;
            while ((len = s.read(buf)) != -1) {
                System.out.println(getdate() + "  服务器说:  "+new String(buf, 0, len,"UTF-8"));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //往Socket里面写数据,需要新开一个线程
    class sendMessThread extends Thread{
        @Override
        public void run() {
            super.run();
            //写操作
            Scanner scanner=null;
            OutputStream os= null;
            try {
                scanner=new Scanner(System.in);
                os= socket.getOutputStream();
                String in="";
                do {
                    in=scanner.next();
                    os.write((""+in).getBytes("UTF-8"));
                    os.write(("哈哈哈哈").getBytes("UTF-8"));
                    os.flush();
                } while (!in.equals("bye"));
            } catch (IOException e) {
                e.printStackTrace();
            }
            scanner.close();
            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    public static String getdate() {
        Date date = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String result = format.format(date);
        return result;
    }
    
    //函数入口
    public static void main(String[] args) {
        //需要服务器的正确的IP地址和端口号
        Client clientTest=new Client("62.234.175.16", 80);
        clientTest.start();
    }
}

②Server


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;


public class AppServer {
	public static void main(String[] args) throws Exception {
		FindFile.init();
		System.out.println("服务启动");
		
		try (ServerSocket serverSocket = new ServerSocket(80);// 监听自己的服务器的80端口

				Socket clientSocket = serverSocket.accept();//ֻ只要发来的数据就接收到这里,网络流--->基本类型数组
				PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
				BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));) {

			System.out.println("客户端连接");
			
			String inputLine;
            String httpstr = "";
			while ((inputLine = in.readLine()) != null) {
				
                                httpstr += inputLine;
                                if(inputLine.equals("") ){ 
                                     break;
                                }
			}
			System.out.println("HTTP协议开始:" + httpstr + "###HTTP协议结束");
			            String[] arr = httpstr.split("\\?");
                        String str = arr[0];
                        String[] strarr = str.split("/");
                        String  url = strarr[strarr.length-1]; 
			System.out.println("提取到的url:" + url );
			            String params = arr[1].split(" HTTP")[0];
			            //key1=22&key2=value2&key3=value3&key4=value4&key5=88
			            String[] pramarr = params.split("&");
                        Learn1.chose2(url,pramarr);
			
		} catch (IOException e) {
			System.out.println(
					"Exception caught when trying to listen on port " + 80 + " or listening for a connection");
			System.out.println(e.getMessage());
		}
		System.out.println("服务退出");

	}
}

 ③FindFile


import java.io.File;
import java.util.HashMap;

public class FindFile {
	public static HashMap<String,Object[]> map = new HashMap<>();
	public static void main(String[] args) throws Exception {
       
    }
	
	public static void init()  {
		 File folder = new File("D:\\eclipse project\\testDemo\\src");
	     try {
			traverseFolder2(folder);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
 
    public static void traverseFolder(File folder) {
        File[] files = folder.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    traverseFolder(file); // 递归遍历子文件夹
                } else {
                    System.out.println(file.getAbsolutePath().split("src")[1]); 
                }
            }
        }
    }
    public static void traverseFolder2(File folder) throws Exception{
        File[] files = folder.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    traverseFolder2(file); 
                } else {
                	String filepath = file.getAbsolutePath().split("src")[1];
                	filepath = filepath.substring(1,filepath.length());
                	filepath = filepath.replace("\\", ".");
                	
                	if(filepath.endsWith("java")) {
                		filepath = filepath.replace(".java", "");
       
                		Class<?> cl = Class.forName(filepath);
                		WebServlet2 annotation =  cl.getAnnotation(WebServlet2.class);
                		if(annotation!=null) {
                			
                			String urlname = annotation.url();
                			//System.out.println(filepath); 
                			//System.out.println("提取到的路径:" + urlname); 
                			map.put(urlname, new Object[] {cl.newInstance(), cl.getMethod("doGet", new Class[] {HSRequest.class}), cl.getMethod("doPost", new Class[] {HSRequest.class})});
                		}
                	}
                    
                }
            }
        }
    }
}

④learn

package tomcat_you;
import java.lang.reflect.Method;
import java.util.Arrays;

public class Learn1 {

	
   public static void chose(String url,String[] pramarr)throws Exception {
	   String[] arr = {"tomcat_you.TestDemo2", "tomcat_you.TestDemo3",  "tomcat_you.TestDemo4"};
		
		Class<?>[] cls = new Class[arr.length];
		for(int i =0;i < cls.length; i++) {
			cls[i] = Class.forName(arr[i]);
			
			WebServlet2 annotation =  cls[i].getAnnotation(WebServlet2.class);
			if(annotation!=null) {
				//模拟挑选出了servlet(带有注解的类)ࣩ
				   String urlname = annotation.url();
				   if(url.equals(urlname)) {
					   Object x = cls[i].newInstance();
					//   HttpServletDemo w = (HttpServletDemo)x;
					  // w.doGet(22, "www");
					   Method method = cls[i].getDeclaredMethod("doGet", new Class[] {HSRequest.class});
					   HSRequest request = new HSRequest();
					   for(String param : pramarr) {
						   String[] arrw = param.split("=");
						   request.put(arrw[0], arrw[1]);
					   }
					   method.invoke(x, request);
				   }
				   
			   }else {
				   continue;
			   }
		}
   }
   
   //tomcat优化
   public static void chose2(String url,String[] pramarr)throws Exception {

			HSRequest request = new HSRequest();
			for(String param : pramarr) {
				String[] arrw = param.split("=");
				request.put(arrw[0], arrw[1]);
		    }
			Object[] arr = FindFile.map.get(url);
			Method m = (Method) arr[1];
			m.invoke(arr[0], request);
   }
}

⑤HSRequest

package tomcat_you;

import java.util.HashMap;

public class HSRequest {
    private HashMap<String,String> map = new HashMap<>();
    public String getParameter(String key) {
    	return map.get(key);
    }
    public void put(String key, String value) {
    	map.put(key, value);
    }
}

⑥HttpServletDemo

package tomcat_you;

public class HttpServletDemo {
	public void doGet(HSRequest request) {
		
	}
	
	public void doPost(HSRequest request){
		
    }
}

⑦WebServlet

package tomcat_you;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD,ElementType.TYPE})
public @interface WebServlet2 {
	public int age();

    // 为name指定初始值ֵ
    public String url() default "小花";
}

 ⑧TestDemo

package tomcat_you;
@WebServlet2(url = "servlet1",age=12)
public class TestDemo2 extends HttpServletDemo{
	public void doGet(HSRequest request){
		String name = request.getParameter("name");
		String age = request.getParameter("age");
		System.out.println("姓名" + name + ",年龄:" + age);
    }
	public void doPost(HSRequest request){
		
    }
}


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

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

相关文章

手机与电脑更改IP地址怎么使用代理IP?

在现代互联网时代&#xff0c;代理IP已成为许多人日常生活和工作中不可或缺的一部分。通过代理IP&#xff0c;用户可以隐藏自己的真实IP地址&#xff0c;并获得更好的网络体验。本文将详细介绍如何在手机和电脑上更改IP地址并使用代理IP。 一、手机使用代理IP 1. 打开手机设置&…

1.C语言——基础知识

C语言基础知识 1.第一个C语言程序2.注释3.标识符4.关键字5.数据类型6.变量7.常量8.运算符9.输入输出输入输出 1.第一个C语言程序 C语言的编程框架 #include <stdio.h> int main() {/* 我的第一个 C 程序 */printf("Hello, World! \n");return 0; }2.注释 单行…

MySQL面试题 | 18.精选MySQL面试题

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

Vue3前端开发,如何获取组件内dom对象以及子组件的属性和方法

Vue3前端开发,借助Ref来获取组件内dom对象&#xff0c;借助defineExpose编译宏可以获取到子组件的属性和方法。 <script setup> import {onMounted, ref} from vue import Base from ./components/Base.vue import SetupDemo from ./components/SetupDemo.vue import Rea…

探索C++中std::string的弱点:你可能未曾注意到的缺点

C中std::string的弱点&#xff1a;你可能未曾注意到的缺点 一、背景二、性能方面的局限三、可变性带来的问题四、内存管理和指针操作五、Unicode和多字节字符集的支持六、其他替代方案七、总结 一、背景 C中std::string是一个非常重要的类&#xff0c;用于表示和处理字符串数据…

无偿分享一个很有用的看源码小技巧

怎么在 idea 里面查看 git 提交记录呢&#xff1f;这个界面是藏在哪里的呢&#xff0c;我的 idea 里面怎么没有呢&#xff1f; 好的&#xff0c;是我疏忽了&#xff0c;我先入为主的认为这个大家应该都知道是怎么来的。 但是确实是有一些同学是不太清楚的&#xff0c;那我这篇…

Java设计模式-单例模式(2)

大家好&#xff0c;我是馆长&#xff01;从今天开始馆长开始对java设计模式的创建型模式中的单例、原型、工厂方法、抽象工厂、建造者的单例模式进行讲解和说明。 单例模式&#xff08;Singleton&#xff09; 定义 某个类只能生成一个实例&#xff0c;该类提供了一个全局访问…

Docker技巧汇总

Docker技巧汇总 前言使用流程安装配置镜像管理创建并运行容器使用容器/常用命令导出和导入查看元数据挂载数据卷端口映射/转发VS Code连接Docker 前言 Docker 是一个开源的应用容器引擎&#xff0c;可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中&#xf…

2024年第十五届机械与智能制造技术国际会议(ICMIMT 2024)

2024年第十五届机械与智能制造技术国际会议(ICMIMT 2024)2024年5月17-19日 南非 开普敦会议官网&#xff1a; 15TH IEEE-ICMIMT 2024http://www.mimt.us/ 近年来&#xff0c;机械和智能制造技术取得了重大进展。先进计算和传感技术的集成带来了更精确、更高效和自动化的制造过…

Pymol-电子密度图展示方法-PDB数据库已发表结构和自己晶体解析得到的结构密度图

简单来说&#xff0c;想要用PyMol展示电子密度图可以归为以下两种&#xff1a; 一是展示PDB数据库中已发表数据的结构和Map的方式 以6sps.pdb为例&#xff0c;在pymol中导入该数据密度图时&#xff0c;可以无需下载对应的密度文件&#xff0c;直接用fetch即可&#xff1a; Py…

Spring 事务管理 @Transactional

事务 Spring 的声明式事务是采用声明的方式来处理事务。这里所说的声明&#xff0c;就是指在配置文件中声明&#xff0c;用在 Spring 配置文件中声明式的处理事务来代替代码式的处理事务。 事务管理不侵入开发的组件。具体来说&#xff0c;业务逻辑对象就不会意识到正在事务管…

CentOS安装Flume

CentOS安装Flume 一、简介二、安装1、下载2、解压3、创建配置文件4、启动flume agent5、验证 一、简介 Flume is a distributed, reliable, and available service for efficiently collecting, aggregating, and moving large amounts of log data. It has a simple and flexi…

2024年南京等保测评机构名单看这里!

时光流逝&#xff0c;已经到了2024年。不少小伙伴在问&#xff0c;2024年南京等保测评机构有哪些&#xff1f;跟2023年一样吗&#xff1f;这里我们小编就给大家汇总了一下&#xff0c;具体地址以及名称看这里就可以啦&#xff01; 2024年南京等保测评机构名单看这里&#xff0…

将TI的电量计Linux驱动从4.4内核移植到5.10

背景 最近公司某产品用到了TI的电量计芯片BQ40Z50&#xff0c;我负责为其开发Linux驱动&#xff0c;搜了下&#xff0c;github上有TI为其写好的开源驱动&#xff0c;太好了。 看了下代码&#xff0c;比较简单&#xff0c;连Makefile都没写&#xff0c;不过这也挺好&#xff0…

超高质量的 8个免费设计素材网站,设计师必备。

设计师一般都去哪里找素材&#xff1f;找高质量且免费的设计素材&#xff0c;就上这8个网站&#xff0c;平面、UI、电商等设计素材都能找到&#xff0c;赶紧收藏一波~ 1、菜鸟图库 https://www.sucai999.com/?vNTYwNDUx 菜鸟图库是我推荐过很多次的网站&#xff0c;主要是站内…

第十三章 MySQL

第十三章 MySQL 下面是创建数据库操作 删除数据库 右上角选择要操作的数据库 如果关闭了这个控制台&#xff0c;下次如何找到它呢 也可以对其改名

C++类包含编译模型实战

文章目录 一、实战概述二、实战步骤&#xff08;一&#xff09;C普通类的包含编译模型1、创建普通类定义文件2、创建普通类实现文件3、创建主程序文件4、运行主程序&#xff0c;查看结果 &#xff08;二&#xff09;C模板类的包含编译模型1、创建模板类定义文件2、创建模板类实…

【Unity】URP报错Object reference not set to an instance of an object

使用URP之后&#xff0c;Unity报错&#xff1a;显示不正常 NullReferenceException: Object reference not set to an instance of an object UnityEngine.Rendering.Universal.UniversalAdditionalCameraData.get_cameraStack () (at Library/PackageCache/com.unity.render-p…

Leetcode 用队列实现栈

题目&#xff1a; 请你仅使用两个队列实现一个后入先出&#xff08;LIFO&#xff09;的栈&#xff0c;并支持普通栈的全部四种操作&#xff08;push、top、pop 和 empty&#xff09;。 实现 MyStack 类&#xff1a; void push(int x) 将元素 x 压入栈顶。 int pop() 移除并…

中使用 MOOTDX库读取通达信的数据,WIN+PYTHON,最新问题排查

M项目概述 - MOOTDXhttps://www.mootdx.com/zh-cn/latest/帮助文档https://www.mootdx.com/zh-cn/latest/​​​​​​​​​​​​​​​​​​​​​ 库的安装 注&#xff1a;我这的安装过程必须要ROOT权限&#xff0c;所以我用管理员的权限运行了控制台 pip install moot…