实现思路 1.进行全局扫描:将项目下所标识有注解的方法进行收集和解析(注意:扫描是一个 非常消耗性能的操作,这种操作应该只需要进行一次 2.进行类的解析 目的:找到哪些类中有哪些方法是标识有注解的,那么这些方法就是用于请求处理的方法, 解析的过程也是同样消耗性能的,思考一下,是否每次请求都要进行一次相同的解析操作 3.将解析的结果进行缓存 这一步非常重要,因为解析的结果将直接为后续的请求服务,在整个项目的运行同期是不能销毁的, 所以我们需要将这些信息缓存再存入到服务器中 一、自定义注解类
package org.nf.framework.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 描述: * * @author lance * 自定义注解 * @Retention –什么时候使用该注解 * @Target –注解用于什么地方 * RetentionPolicy.RUNTIME : 始终不会丢弃,运行期也保留该注解, * 因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。 * ElementType.METHOD:用于描述方法 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface UrlMapping { String value(); }
二、扫描工具类,得到项目中所有的包名和类名
package org.nf.framework.utils; import java.io.File; import java.net.URLDecoder; import java.util.ArrayList; import java.util.List; /** * 扫描工具类,用于扫描指定包下面的所有类,包括子包 * @author lance * */ public class ScanUtil { /** * 存放所有类的类名 */ private static List<String> list = new ArrayList<String>(); /** * 扫描 * @param packagePath * @return */ public static List<String> scanPackage(String packages) { String[] packs = packages.split(","); for (String pack : packs) { String path = toPackagePath(pack); try { toClassPath(path); } catch (Exception e) { e.printStackTrace(); } } return list; } /** * 将路径转换成包名 * @param packagePath * @return */ private static String toPackagePath(String packagePath) { packagePath = packagePath.replace(".", File.separator); return getRealPath()+packagePath; } /** * 遍历目录将类名存入List中 * @param classPath * @throws Exception */ private static void toClassPath(String classPath) throws Exception { classPath = URLDecoder.decode(classPath, "utf-8"); // listFiles()获取路径下的所有文件或文件夹,返回的是一个File[]数组 File[] fs = new File(classPath).listFiles(); if (fs != null) { for (File file : fs) { // file.isDirectory()方法判断当前额的file对象是否是一个文件夹 if (file.isDirectory()) { // 获取文件夹的绝度路径 // 递归调用 toClassPath(file.getAbsolutePath()); } else { // 将文件名转换成完整类名 String path = toClassName(file); if (path != null) list.add(path); } } } } /** * 将文件名转换成完整类名 * @param file * @return * @throws Exception */ private static String toClassName(File file) throws Exception { if (file.getName().endsWith(".class")) { String path = URLDecoder.decode(getRealPath(), "utf-8"); path = new File(path).getAbsolutePath() + File.separator; path = file.getAbsolutePath().substring(path.length(), file.getAbsolutePath().length()); String className = path.replace(File.separator, "."); className = className.substring(0, className.length() - 6); return className; } else { return null; } } /** * 获取当前项目的classes目录 * @return */ private static String getRealPath(){ return ScanUtil.class.getClassLoader().getResource("").getPath(); } }
三、servlet总控制器(相当于中央处理器,处理所有的servlet请求,核心)
package org.nf.framework.web; import org.nf.framework.annotation.UrlMapping; import org.nf.framework.utils.ScanUtil; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 描述: * 总控制器 * * @author lance * @create 2018-08-31 9:48 实现思路 1.进行全局扫描:将项目下所标识有注解的方法进行收集和解析(注意:扫描是一个 非常消耗性能的操作,这种操作应该只需要进行一次 ) 2.进行类的解析 目的:找到哪些类中有哪些方法是标识有注解的,那么这些方法就是用于请求处理的方法, 解析的过程也是同样消耗性能的,思考一下,是否每次请求都要进行一次相同的解析操作 3.将解析的结果进行缓存 这一步非常重要,因为解析的结果将直接为后续的请求服务,在整个项目的运行同期是不能销毁的, 所以我们需要将这些信息缓存再存入到服务器中 */ public class DispatcherServlet extends HttpServlet { private static final Map<String, Method> mapper = new HashMap<>(); @Override public void init(ServletConfig config) throws ServletException { //1.全局的扫描(空代表全局,也可以给某个包的值) List<String> className = scan(""); //2.解析类中有注解的方法 resolve(className); System.out.println("DispatcherServlet初始化完成。。。。"); } @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取请求的url,这个path其实就对应了mapper中的key String path = req.getServletPath(); //根据key取出相应的method并调用处理请求 //根据相应的key取出相应method,并调用方法 invokeTargetMethod(req,resp,mapper.get(path)); } /** * 进行类扫描 * */ private List<String> scan(String packageName){ return ScanUtil.scanPackage(packageName); } /** * 解析类中的注解方法 * */ private void resolve(List<String> className){ for (String s : className) { try { //进行类加载 Class<?> clazz= Class.forName(s); //获得类中的所有的方法 Method[] methods = clazz.getMethods(); for (Method method : methods) { if(method.isAnnotationPresent(UrlMapping.class)){ //获得所有注解方法的上value值,也就是请求url的值 String url = method.getAnnotation(UrlMapping.class).value(); //缓存到map集合中 mapper.put(url,method); } } } catch (ClassNotFoundException e) { throw new RuntimeException(e.getMessage()); } } } /** *调用具体某目标的方法 * */ private void invokeTargetMethod(HttpServletRequest request,HttpServletResponse response,Method method){ try { //先获得该类中的实例 Object instance = method.getDeclaringClass().newInstance(); //回调方法 method.invoke(instance,request,response); } catch (InstantiationException e) { throw new RuntimeException(e.getMessage()); } catch (IllegalAccessException e) { throw new RuntimeException(e.getMessage()); } catch (InvocationTargetException e) { throw new RuntimeException(e.getMessage()); } } }
四、具体servlet请求实现类
package org.nf.framework.Test; import org.nf.framework.annotation.UrlMapping; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 描述: * 具体处理请求 * * @author lance * @create 2018-08-31 11:16 */ public class Collectors { @UrlMapping("/login") public void Login(HttpServletRequest request, HttpServletResponse response){ String name = request.getParameter("userName"); String password = request.getParameter("password"); System.out.println(name); System.out.println(password); System.out.println("login....."); } @UrlMapping("/regist") public void regist(HttpServletRequest request, HttpServletResponse response){ System.out.println("....."); } }
原文地址:https://www.cnblogs.com/gepuginy/p/9726557.html
时间: 2024-10-10 00:46:25