一、Tomcat运行原理分析
1. Tomcat是运行在JVM中的一个进程。它定义为【中间件】,顾名思义,是一个在Java项目与JVM之间的中间容器。
2. Web项目的本质,是一大堆的资源文件和方法。Web项目没有入口方法(main方法),,意味着Web项目中的方法不会自动运行起来。
3. Web项目部署进Tomcat的webapp中的目的是很明确的,那就是希望Tomcat去调用
写好的方法去为客户端返回需要的资源和数据。
4. Tomcat可以运行起来,并调用写好的方法。那么,Tomcat一定有一个main方法。
5. 对于Tomcat而言,它并不知道我们会有什么样的方法,这些都只是在项目被部署进webapp下后才确定的,由此分析,必然用到了Java的反射来实现类的动态加载、实例化、获取方法、调用方法。但是我们部署到Tomcat的中的Web项目必须是按照规定好的接口来进行编写,以便进行调用
6. Tomcat如何确定调用什么方法呢。这取却于客户端的请求,http://127.0.0.1:8080/JayKing.Tomcat.Study/index.java?show这样的一个请求,通过http协议,在浏览器发往本机的8080端口,携带的参数show方法,包含此方法的路径为JayKing.Tomcat.Study,文件名为:index.java。
二、模拟Tomcat运行
1.客户端类
package JayKing.Tomcat.Study; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Writer; import java.net.Socket; import java.net.UnknownHostException; import java.util.Scanner; public class Client { private static int port = 5228; private static String host = "127.0.0.1"; //http://127.0.0.1:8080/JayKing.Tomcat.Study/index.java?show public static void main(String[] args) { try { Socket con=new Socket(host,port); System.out.println("请输入URL地址:"); Scanner scanner=new Scanner(System.in); String info=scanner.nextLine().trim(); Writer writer = new OutputStreamWriter(con.getOutputStream()); writer.write(info); writer.flush(); writer.close(); } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
2.服务器类
package JayKing.Tomcat.Study; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.ServerSocket; import java.net.Socket; public class TomcatTest { private static int post = 5228; private static UrlUtil urlutil = new UrlUtil(); public static void main(String[] args) { System.out.println(" My Tomcat is Running"); try { ServerSocket server = new ServerSocket(post); while (true) { Socket socket = server.accept();// 服务器每接受一次请求,就创建一个socket对象 InputStream in = socket.getInputStream(); BufferedReader br = new BufferedReader( new InputStreamReader(in)); String info = null; String infoline = br.readLine(); while (infoline != null) { info =info+infoline; infoline = br.readLine(); } UrlBean url = urlutil.readString(info); if (url != null) { String path=url.getPath(); String className = url.getFileName(); String methodName = url.getParameter().trim(); ClassLoader classloader=ClassLoader.getSystemClassLoader(); try { classloader.loadClass(path+"."+className); Class<?> getclass=Class.forName(path+"."+className); Method method=getclass.getMethod(methodName, null); method.invoke(getclass.newInstance(), null); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } } else { } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
3.工具类
package JayKing.Tomcat.Study; //格式:协议://主机号:端口号/目录路径/文件名 //例如: http://127.0.0.1:8080/Test/Manage/index.jsp public class UrlUtil { public UrlBean readString(String info) { UrlBean url = null; int tag1 = info.indexOf(":"); int tag2 = info.lastIndexOf(":"); int tag3 = info.indexOf("/", tag2); int tag4 = info.lastIndexOf("/"); int tag5 = info.indexOf("?"); int tag6=info.lastIndexOf("."); String Protocol = info.substring(0, tag1); String Host = info.substring(tag1 + 3, tag2); String Port = info.substring(tag2 + 1, tag3); String Path = info.substring(tag3 + 1, tag4); String FileName = info.substring(tag4 + 1, tag6); String Parameter = info.substring(tag5 + 1, info.trim().length()); if (Host != null && Path != null && FileName != null) { if (Protocol == null) { Protocol = "http"; } if (Port == null) { Port = "8080"; } url = new UrlBean(Protocol, Host, Port, Path, FileName, Parameter); return url; } return url; } }
4.Model类
package JayKing.Tomcat.Study; //格式:协议://主机号:端口号/目录路径/文件名 //例如: http://127.0.0.1:8080/Test/Manage/index.jsp?a=1&b=2 public class UrlBean { private String Protocol; private String Host; private String Port; private String Path; private String FileName; private String Parameter; public UrlBean(String protocol, String host, String port, String path, String fileName, String parameter) { super(); Protocol = protocol; Host = host; Port = port; Path = path; FileName = fileName; Parameter = parameter; } public UrlBean() { } public String getProtocol() { return Protocol; } public void setProtocol(String protocol) { Protocol = protocol; } public String getHost() { return Host; } public void setHost(String host) { Host = host; } public String getPort() { return Port; } public void setPort(String port) { Port = port; } public String getPath() { return Path; } public void setPath(String path) { Path = path; } public String getFileName() { return FileName; } public void setFileName(String fileName) { FileName = fileName; } public String getParameter() { return Parameter; } public void setParameter(String parameter) { Parameter = parameter; } }
5.测试方法类
package JayKing.Tomcat.Study; public class index { public void show() { System.out.println("方法已经被执行!"); } }
6.运行结果
三、Tomcat原理总结
1. Tomcat需要main方法启动。
2. Tomcat需要监听本机上的某个端口。
3. Tomcat需要抓取此端口上来自客户端的链接并获得请求调用的方法与参数。
4. Tomcat需要根据请求调用的方法,动态地加载方法所在的类,完成累的实例化并通过该实例获得需要的方法最终将请求传入方法执行。
5. 将结果返回给客户端(jsp/html页面、json/xml字符串)。