前言
上一篇讲了tomcat的理论核心,tomcat是由一层层容器套成的跟俄罗斯套娃似的,服务端有server,service,engine,context,servlet等,但是web端没有仔细讲。一个url怎么进入程序,并是怎样被解析找到对应的类的方法的?下面我们动手写一个。
4步走
1.获取配置文件中的url和对应的类名,并创建servletMapping文件
2.死循环等待用户请求
2.封装serverSocket的inputstream,outputstream为HttpRequest,HttpResponse
4.获取httpRequest的访问方式和方法,根据mapping动态调用对应的servlet的doGet或doPost
4个核心概念
1.serverSocket inputStream outputStream
2.HttpRequest HttpResponse
3.servletMapping
4.servlet doGet doPost
代码实现
tomcat类:
public class HLPTomcat {
private int port = 8084;
private ServerSocket serverSocket;
private Map<String,HLPServlet> servletMapping = new HashMap<String,HLPServlet>();
private Properties webXml = new Properties();
private void init(){
//加载web.xml,初始化servletmapping对象
try{
// String basePath = this.getClass().getResource("conf").getPath();
String basePath =Thread.currentThread().getContextClassLoader().getResource("conf/tomcat.properties").getPath();
FileInputStream fis = new FileInputStream(basePath);
webXml.load(fis);
}catch (Exception e){
e.printStackTrace();
}
for(Object k : webXml.keySet()){
String key = k.toString();
if(key.endsWith(".url")){
String servletName = key.replaceAll("\\.url$","");
String url = webXml.getProperty(key);
String className = webXml.getProperty(servletName + ".className");
HLPServlet obj = null;
try {
obj = (HLPServlet) Class.forName(className).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
servletMapping.put(url,obj);
}
}
}
//3.把serverSocket的inputstream, outputstream 封装成request, response对象
private void process(Socket client)throws Exception
{
InputStream ins = client.getInputStream();
OutputStream outs = client.getOutputStream();
HLPRequest hlpRequest = new HLPRequest(ins);
HLPResponse hlpResponse = new HLPResponse(outs);
//4.动态调用doget,dopost
String url = hlpRequest.getUrl();
if(servletMapping.containsKey(url)){
servletMapping.get(url).service(hlpRequest,hlpResponse);
}else{
hlpResponse.write("404-Not Found");
}
outs.flush();
outs.close();
client.close();
}
public void start() {
// 1.初始化
init();
try {
serverSocket = new ServerSocket(this.port);
System.out.println("tomcat is started and the port is " + this.port);
// Socket socket = serverSocket.accept();
// System.out.println(socket);
//2.死循环等待用户请求
while(1==1){
Socket client = serverSocket.accept();
process(client);
// OutputStream op = client.getOutputStream();
// op.write("Hello".getBytes());
// op.close();
// client.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new HLPTomcat().start();
}
}
httpservlet类:
public abstract class HLPServlet {
public void service(HLPRequest request, HLPResponse response)throws Exception{
if("Get".equalsIgnoreCase(request.getMethod())){
doGet(request,response);
}else{
doPost(request,response);
}
}
public abstract void doGet (HLPRequest request, HLPResponse response);
public abstract void doPost (HLPRequest request, HLPResponse response);
}
httpRequest类:
public class HLPRequest {
String method;
String url;
public HLPRequest(InputStream ins){
try{
byte[] buff = new byte[1024];
String content = "";
int len = 0;
if ((len = ins.read(buff)) >0){
content = new String(buff,0,len);
//System.out.println(content);
}
String line = content.split("\\n")[0];
String[] arr = line.split("\\s");
this.method = arr[0];
this.url = arr[1].split("\\?")[0];
}catch (Exception e){
e.printStackTrace();
}
}
public String getUrl(){
return this.url;
}
public String getMethod(){
return this.method;
}
public Map<String,String> getParameter(){
return null;
}
}
httpResponse类:
public class HLPResponse {
private OutputStream outs;
public HLPResponse(OutputStream outs){
this.outs=outs;
}
public void write(String outString)throws Exception{
outs.write(outString.getBytes());
}
}
firstServlet类:
public class FirstServlet extends HLPServlet {
@Override
public void doGet(HLPRequest request, HLPResponse response) {
try {
response.write("this is first servlet");
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void doPost(HLPRequest request, HLPResponse response) {
try {
response.write("this is first servlet");
} catch (Exception e) {
e.printStackTrace();
}
}
}
secondServlet类:
public class SecondServlet extends HLPServlet {
@Override
public void doGet(HLPRequest request, HLPResponse response) {
try {
response.write("this is second servlet");
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void doPost(HLPRequest request, HLPResponse response) {
try {
response.write("this is second servlet");
} catch (Exception e) {
e.printStackTrace();
}
}
}
代码中的小感悟
1.如何把本地文件加载到代码中
- 获取本地文件的路径
String basePath =Thread.currentThread().getContextClassLoader().getResource("conf/tomcat.properties").getPath();
- 生成inputstream
FileInputStream fis = new FileInputStream(basePath);
- 把inputstream读到properties文件中
private Properties webXml = new Properties();
webXml.load(fis);
2.mapping是一个hashmap, key是string, value是一个servlet实例
如何应用反射创建的类实例?
obj = (HLPServlet) Class.forName(className).newInstance();
反射
1.类加载
–1.加载:加载代码到方法区;在堆里创建一个类文件的对象
–2.连接
~1.验证
~2.准备 为静态变量,静态方法初始化
~3.解析 把a=b 变成1
–3.初始化 ~1.开辟空间
~2.赋初值
2.类初始化时机–1.实例类–2实例自类–3.调用静态成员变量–4.调用静态成员方法–5.反射强制创建某个类或接口的java.lang.class对象
3.类加载器
–1.bootstrap classLoader 加载核心类库 rt.jar
–2.extansion classLoader 扩展加载器
–3.system classLoader 系统加载器
4.配置文件使类不需要更改
5.反射:运行时随便一个class文件,反射都可以解剖,拿到里面所有的属性和方法/动态获取一个类中的所有内容并运行
{
FileReader f = new FileReader("dd");
Properties p = new Properties();
p.load(f);
f.close();
String className = p.getProperty("name");
String method = p.getProperty("method");
Class c = Class.forName(className);
Object o = c.newInstance();
Method m = c.getMethod(method);
m.invoke(o);
}
类文件对象的描述文件是java.lang.Java6.获取一个类的class文件对象的三种方式:
–1.对象获取Person p = new Person();p.getClass();
–2.类名获取Person.class();
–3.class类的静态方法获取Class c = Class.forName(“className”);