利用反射机制重构DispatcherServlet,使得将来添加新的业务时DispatcherServlet 不必再添加分支判断(不进行修改) 实现: 1:新建包com.webserver.annotation 2:在annotation包下添加两个注解 @Controller:用于标注哪些类是处理业务的Controller类 @RequestMapping:用于标注处理某个业务请求的业务方法 3:将com.webserver.controller包下的所有Controller类添加注解@Controller 并将里面用于处理某个业务的方法标注@RequestMapping并指定该方法处理的请求 4:DispatcherServlet在处理请求时,先扫描controller包下的所有Controller类 并找到处理该请求的业务方法,使用反射调用.1.1项目目录 1.2Java文件 1.2.1Controller(注解)
package com.webserver.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {
}
1.2.2RequestMapping(注解)
package com.webserver.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
String value();
}
1.2.3ClientHandler
package com.webserver.core;
import com.webserver.http.EmptyRequestException;
import com.webserver.http.HttpServletRequest;
import com.webserver.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.net.Socket;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
public class ClientHandler implements Runnable{
private Socket socket;
public ClientHandler(Socket socket){
this.socket = socket;
}
public void run() {
try {
//1解析请求
HttpServletRequest request = new HttpServletRequest(socket);
HttpServletResponse response = new HttpServletResponse(socket);
//2处理请求
DispatcherServlet servlet = new DispatcherServlet();
servlet.service(request,response);
//3发送响应
response.response();
} catch (IOException e) {
e.printStackTrace();
} catch (EmptyRequestException e) {
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} finally {
try {
//按照HTTP协议要求,一次交互后要断开连接
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
1.2.4DispatcherServlet
package com.webserver.core;
import com.webserver.annotations.Controller;
import com.webserver.annotations.RequestMapping;
import com.webserver.controller.ArticleController;
import com.webserver.controller.ToolsController;
import com.webserver.controller.UserController;
import com.webserver.http.HttpServletRequest;
import com.webserver.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.nio.file.Files;
public class DispatcherServlet {
private static File rootDir;
private static File staticDir;
static {
try {
rootDir = new File(
ClientHandler.class.getClassLoader()
.getResource(".").toURI()
);
staticDir = new File(rootDir, "static");
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
public void service(HttpServletRequest request, HttpServletResponse response) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException {
String path = request.getRequestURI();
//根据请求路径判断是否为处理某个业务
File dir = new File(rootDir,"/com/webserver/controller");
File[] files = dir.listFiles(f->f.getName().endsWith(".class"));
for(File file : files){
String fileName = file.getName();
String className = fileName.substring(0,fileName.indexOf("."));
Class cls = Class.forName("com.webserver.controller."+className);
//判断当前类是否为Controller(是否被@Controller标注)
if(cls.isAnnotationPresent(Controller.class)){
//获取该类中所有方法
Method[] methods = cls.getDeclaredMethods();
for(Method method : methods){
//判断当前方法是否为处理业务的方法(是否被@RequestMapping标注)
if(method.isAnnotationPresent(RequestMapping.class)){
//获取注解@RequestMapping
RequestMapping rm = method.getAnnotation(RequestMapping.class);
String value = rm.value();
//判断该注解上的参数值是否与本次请求路径一致?若一致说明就是该方法处理这个请求
if(value.equals(path)){
//实例化当前Controller
Object controller = cls.newInstance();
//调用当前方法处理该请求
method.invoke(controller,request,response);
return;//当业务处理完毕直接return,防止执行下面请求静态资源的逻辑
}
}
}
}
}
File file = new File(staticDir, path);
System.out.println("资源是否存在:" + file.exists());
if (file.isFile()) {
//将请求的实际文件设置到response的正文上等待响应
response.setContentFile(file);
} else {
file = new File(staticDir, "/root/404.html");
//将404内容设置到response上等待响应
response.setStatusCode(404);
response.setStatusReason("NotFound");
response.setContentFile(file);
}
}
}
1.3HTML文件
和之前的版本一样
2.V26版本重构代码 上一个版本那种DispatcherServlet每次处理请求时都要扫描controller包,这样性能 底下.因此改为仅扫描一次. 实现: 1:在com.webserver.core包下新建类HandlerMapping 2:定义静态属性Map mapping key:请求路径 value:MethodMapping(内部类),记录处理该请求的方法对象和该方法所属对象 3:在静态块中初始化,完成原DispatcherServlet扫描controller包的工作并初始化map 4:提供静态方法:getMethod可根据请求路径获取处理该请求的方法 5:在DispatcherServlet中处理业务时只需要根据请求获取对应的处理方法利用反射 机制调用即可2.1项目目录 2.2Java文件 2.2.1ClientHandler
package com.webserver.core;
import com.webserver.http.EmptyRequestException;
import com.webserver.http.HttpServletRequest;
import com.webserver.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.net.Socket;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
public class ClientHandler implements Runnable{
private Socket socket;
public ClientHandler(Socket socket){
this.socket = socket;
}
public void run() {
try {
//1解析请求
HttpServletRequest request = new HttpServletRequest(socket);
HttpServletResponse response = new HttpServletResponse(socket);
//2处理请求
DispatcherServlet servlet = new DispatcherServlet();
servlet.service(request,response);
//3发送响应
response.response();
} catch (IOException e) {
e.printStackTrace();
} catch (EmptyRequestException e) {
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} finally {
try {
//按照HTTP协议要求,一次交互后要断开连接
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2.2.2DispatcherServlet
package com.webserver.core;
import com.webserver.annotations.Controller;
import com.webserver.annotations.RequestMapping;
import com.webserver.controller.ArticleController;
import com.webserver.controller.ToolsController;
import com.webserver.controller.UserController;
import com.webserver.http.HttpServletRequest;
import com.webserver.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.nio.file.Files;
public class DispatcherServlet {
private static File rootDir;
private static File staticDir;
static {
try {
rootDir = new File(
ClientHandler.class.getClassLoader()
.getResource(".").toURI()
);
staticDir = new File(rootDir, "static");
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
public void service(HttpServletRequest request, HttpServletResponse response) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException {
String path = request.getRequestURI();
//path:/myweb/index.html
//判断当前请求是否为请求业务
HandlerMapping.MethodMapping mm = HandlerMapping.getMethod(path);
if(mm!=null){
Method method = mm.getMethod();
Object controller = mm.getController();
method.invoke(controller,request,response);
return;
}
File file = new File(staticDir, path);
System.out.println("资源是否存在:" + file.exists());
if (file.isFile()) {
//将请求的实际文件设置到response的正文上等待响应
response.setContentFile(file);
} else {
file = new File(staticDir, "/root/404.html");
//将404内容设置到response上等待响应
response.setStatusCode(404);
response.setStatusReason("NotFound");
response.setContentFile(file);
}
}
}
2.2.3HandlerMapping
package com.webserver.core;
import com.webserver.annotations.Controller;
import com.webserver.annotations.RequestMapping;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
public class HandlerMapping {
public static Map mapping = new HashMap();
static{
initMapping();
}
private static void initMapping(){
try {
File rootDir = new File(HandlerMapping.class.getClassLoader().
getResource(".").toURI());
File dir = new File(rootDir,"/com/webserver/controller");
File[] files = dir.listFiles(f->f.getName().endsWith(".class"));
for(File file : files){
String fileName = file.getName();
String className = fileName.substring(0,fileName.indexOf("."));
Class cls = Class.forName("com.webserver.controller."+className);
//判断当前类是否为Controller(是否被@Controller标注)
if(cls.isAnnotationPresent(Controller.class)){
//将该Controller实例化
Object controller = cls.newInstance();
//获取该类中所有方法
Method[] methods = cls.getDeclaredMethods();
for(Method method : methods){
//判断当前方法是否为处理业务的方法(是否被@RequestMapping标注)
if(method.isAnnotationPresent(RequestMapping.class)){
//获取注解@RequestMapping
RequestMapping rm = method.getAnnotation(RequestMapping.class);
String value = rm.value();//该方法处理的请求路径
MethodMapping mm = new MethodMapping(method,controller);
mapping.put(value,mm);
}
}
}
}
} catch (URISyntaxException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public static MethodMapping getMethod(String uri){
return mapping.get(uri);
}
public static void main(String[] args) {
mapping.forEach(
(k,v)->{
System.out.println("请求路径"+k);
System.out.println("对应的处理方法:"+v.getMethod().getName());
}
);
}
public static class MethodMapping{
//method.invoke(controller,...);
private Method method; //方法对象
private Object controller; //方法所属的Controller对象
public MethodMapping(Method method, Object controller) {
this.method = method;
this.controller = controller;
}
public Method getMethod() {
return method;
}
public Object getController() {
return controller;
}
}
}
2.3HTML文件
没有改动



