之前写过一篇博客是servlet的抽取
但是在使用的时候,每次都要加上method=xxx
现在就想基于之前的方法进行改进,实现类似于springmvc那样的效果
直接根据请求,找到对应的方法,来执行,
所以现在就是用注解的方式对之前的serlvet抽取进行改进
public class ClassScanner { /** * 获得包下面的所有的class * @param * @return List包含所有class的实例 */ public static List<Class<?>> getClasssFromPackage(String packageName) { List<Class<?>> clazzs = new ArrayList<>(); // 是否循环搜索子包 boolean recursive = true; // 包名对应的路径名称 String packageDirName = packageName.replace('.', '/'); Enumeration<URL> dirs; try { dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName); while (dirs.hasMoreElements()) { URL url = dirs.nextElement(); String protocol = url.getProtocol(); if ("file".equals(protocol)) { String filePath = URLDecoder.decode(url.getFile(), "UTF-8"); findClassInPackageByFile(packageName, filePath, recursive, clazzs); } } } catch (Exception e) { e.printStackTrace(); } return clazzs; } /** * 在package对应的路径下找到所有的class */ public static void findClassInPackageByFile(String packageName, String filePath, final boolean recursive, List<Class<?>> clazzs) { File dir = new File(filePath); if (!dir.exists() || !dir.isDirectory()) { return; } // 在给定的目录下找到所有的文件,并且进行条件过滤 File[] dirFiles = dir.listFiles(new FileFilter() { public boolean accept(File file) { boolean acceptDir = recursive && file.isDirectory();// 接受dir目录 boolean acceptClass = file.getName().endsWith("class");// 接受class文件 return acceptDir || acceptClass; } }); for (File file : dirFiles) { if (file.isDirectory()) { findClassInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, clazzs); } else { String className = file.getName().substring(0, file.getName().length() - 6); try { clazzs.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + "." + className)); } catch (Exception e) { e.printStackTrace(); } } } } }
@WebServlet("*.do") public class DispatherServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String requestURI = req.getRequestURI(); String contextPath = req.getContextPath(); //为了获取请求地址中,我们需要的部分,主要是为了取出ip端口项目名等无关信息 String mappingPath = requestURI.substring(contextPath.length(),requestURI.length()); //找到controller包下所有的类 List<Class<?>> classsFromPackage = ClassScanner.getClasssFromPackage("com.kehao.controller"); //对每一个类去看他是否有MyCompoent注解 classsFromPackage.stream().filter(clz-> clz.isAnnotationPresent(MyCompoent.class)).forEach( //对于符合要求的类,获取他们的被MyRequestMapping注解标注的方法,如果注解的值和请求地址相同就调用该方法 (clz)->{ Arrays.stream(clz.getDeclaredMethods()). filter(method -> method.isAnnotationPresent(MyRequestMapping.class)). filter(method->mappingPath.equals(method.getAnnotation(MyRequestMapping.class).value())). forEach(method -> { try { method.invoke(clz.newInstance(),req,resp); } catch (Exception e) { e.printStackTrace(); } }); } ); } }
@MyCompoent public class HelloController { @MyRequestMapping("/hello.do") public void hello(HttpServletRequest req, HttpServletResponse resp) throws Exception { resp.getWriter().println("hello,i'm in HelloController"); } }
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface MyRequestMapping { String value(); } @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface MyCompoent { }
很明显,这个代码还存在着明显的不足,需要改进,首先每次调用都需要扫描类和方法,需要新建了一个对象,而这些过程是重复的,还可以继续优化