手写spring简易版本

tech2024-03-10  55

自定义几个注解 手写一个DispatcherServlet,代码结构如下:

基本思路流程:

一、 读取配置文件

1.类加载器获取initParam中定义的资源文件 2.利用Properties的load方法加载io对象,映射key value 3.获取配置文件里的包路径

二、初始化ioc容器

定义一个map集合

三、扫描包下的class

1.类加载器根据包路径得到url.getFile全路径 2.利用File遍历出该路径下所有文件和文件夹 3.如果是文件夹则拼接路径递归遍历,如果是文件则判断是否以.class结尾,是则将全类名放入list集合中

四、实例化对象并放入ioc

1.遍历list集合,Class.forName("全类名"),通过反射获取其类名和实例对象 2.判断是否加了@YService、@YController注解,如果注解加在了接口上则默认无效, 3.如果定义了别名则获取,没有则默认类名首字母小写,并且遍历当前类所实现的所有接口,将子类对象值赋予存入ioc

五、扫描放入ioc中的对象,初始化其属性

1.遍历ioc集合,获取声明的所有属性 2.反射判断是否加入@YAutowired注解,是则获取当前属性名,将ioc中存入的值赋予属性

六、初始化handleMapping,将url和menthod一一对应

1.定义一个handleMapping的map集合 2.遍历ioc集合,根据对象的class对象判断是否有@YController注解 3.判断是否有@YRequestMapping注解,有url值的话则获取baseUrl 4.反射获取对象中所有方法,判断方法上是否有@YRequestMapping注解,获取其url值,和baseUrl一起拼接成一个uri,将其和method一起放入handleMapping集合

------------------至此init初始化阶段完成,进入service方法---------- 1.获取请求的url和项目名称,得到uri 2.判断handle集合中是否有这个uri,没有就404,有则取出其method 3.根据method获得对象名,获取请求的参数执行invoke方法

大体代码逻辑如下:

完整代码我发布在github:https://github.com/yangzhenyan/spring.git

@YController @YRequestMapping("item") public class ItemController { @YAutowired private ItemService itemService; private ItemService itemService1; //查询 @YRequestMapping("query") public void query(HttpServletRequest request, HttpServletResponse response, @YRequestParam("name") String name, @YRequestParam("id") String id) { try { response.setContentType("text/html;charset=UTF-8"); response.getWriter().write("Amos的名字叫做:" + name + " id为:" + id); } catch (IOException e) { e.getCause().getMessage(); } } } public class YzyDispatcherServlet extends HttpServlet { private Properties properties = new Properties(); //2、初始化ioc容器 private Map<String, Object> iocMap = new HashMap<>(); //存放全类名 private List<String> classNameList = new ArrayList<>(); //handleMapping集合 private Map<String, Method> handleMap = new HashMap<>(); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //7、执行相关方法 try { String requestURI = req.getRequestURI(); //获取项目名 "/项目名" String contextPath = req.getContextPath(); //获取请求的uri String uri = requestURI.replace(contextPath, ""); //如果请求的uri不包含在handleMapping集合 if (!handleMap.containsKey(uri)) { resp.getWriter().write("404 Not Found !!"); return; } Method method = handleMap.get(uri); Map<String, String[]> params = req.getParameterMap(); String beanName = toLowerLetters(method.getDeclaringClass().getSimpleName()); method.invoke(iocMap.get(beanName),new Object[]{req,resp,params.get("name")[0],params.get("id")[0]}); } catch (Exception e) { resp.getWriter().write("500 Internal Server Exception !!"); e.printStackTrace(); } } @Override public void init(ServletConfig config) throws ServletException { //1、读取配置文件 doReadConfig(config.getInitParameter("myConfigLocation")); //3、扫描包路径下的类 将.替换成/ String scanPackage = properties.getProperty("scanPackage").trim(); doScanner(scanPackage.replaceAll("\\.", "/")); //4、创建实例化对象将其注入到ioc容器中 doInstance(); //5、DI 扫描容器中对象 对其属性赋值 doAutowired(); //6、初始化handleMapping 将url和method一一映射 doHandleMapping(); System.out.println("Spring Framework init......"); } //1、读取配置文件 private void doReadConfig(String configLocation) { ClassLoader classLoader = getClass().getClassLoader(); InputStream inputStream = classLoader.getResourceAsStream(configLocation); try { properties.load(inputStream); } catch (IOException e) { e.printStackTrace(); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } //3、扫描包路径下的类 private void doScanner(String scanPackage) { // scanPackage = scanPackage.replace(".", "/"); URL url = getClass().getClassLoader().getResource("/" + scanPackage); //url.getFile() 获取此文件名URL File filePath = new File(url.getFile()); File[] files = filePath.listFiles(); for (File file : files) { if (file.isDirectory()) { //如果是文件夹 则在该文件夹的路径下递归扫描 String s = scanPackage + "/" + file.getName(); doScanner(s); } //再判断是不是以.class结尾的文件 if (file.getName().endsWith(".class")) { //拼接全类名 去除.class后缀 String className = scanPackage.replace("/", ".") + "." + file.getName().replace(".class", ""); classNameList.add(className); } } } //4、实例化对象并注入ioc中 private void doInstance() { if (classNameList.isEmpty()) { return; } //遍历全类名list for (String name : classNameList) { try { //根据全类名获取对应字节码对象 Class<?> aClass = Class.forName(name); //判断是不是加了@YService或@YController注解 if (!aClass.isAnnotationPresent(YService.class) & !aClass.isAnnotationPresent(YController.class)) { continue; } //如果是接口上加的注解 则不放入ioc if (aClass.isInterface()) { continue; } //将对象放入ioc中 ioc中组件名默认首字母小写 //如果不同包下有相同类名 自定义类名 String beanName = null; if (aClass.isAnnotationPresent(YService.class)) { beanName = toLowerLetters(aClass.getSimpleName()); if (!"".equals(aClass.getAnnotation(YService.class).value())) { beanName = aClass.getAnnotation(YService.class).value(); } } else if (aClass.isAnnotationPresent(YController.class)) { beanName = toLowerLetters(aClass.getSimpleName()); if (!"".equals(aClass.getAnnotation(YController.class).value())) { beanName = aClass.getAnnotation(YController.class).value(); } } //获取对象 Object instance = aClass.newInstance(); iocMap.put(beanName, instance); //获得这个对象实现的所有接口 将其接口也放入ioc 接口的值为子类值 for (Class<?> inter : aClass.getInterfaces()) { beanName = toLowerLetters(inter.getSimpleName()); iocMap.put(beanName, instance); } } catch (Exception e) { e.printStackTrace(); } } } //5、DI 扫描容器中对象 对其属性赋值 private void doAutowired() { if (iocMap.isEmpty()) { return; } for (Map.Entry<String, Object> entry : iocMap.entrySet()) { //获取对象中的属性 Field[] fields = entry.getValue().getClass().getDeclaredFields(); for (Field field : fields) { //如果加了@YAutowired注解就给属性赋值 if (field.isAnnotationPresent(YAutowired.class)) { //暴力访问 field.setAccessible(true); try { //获取该属性beanName String beanName = toLowerLetters(field.getType().getSimpleName()); field.set(entry.getValue(), iocMap.get(beanName)); } catch (IllegalAccessException e) { e.printStackTrace(); continue; } } } } } //6、初始化handleMapping 将url和method一一映射 private void doHandleMapping() { if (iocMap.isEmpty()) { return; } for (Map.Entry<String, Object> entry : iocMap.entrySet()) { Class<?> aClass = entry.getValue().getClass(); if (!aClass.isAnnotationPresent(YController.class)) { continue; } //判断类路径上是否有@YRequestMapping注解 有就获取 String baseUrl = null; if (aClass.isAnnotationPresent(YRequestMapping.class)) { baseUrl = aClass.getAnnotation(YRequestMapping.class).value(); } //判断方法上@YRequestMapping注解 Method[] methods = aClass.getMethods(); String methodUrl = null; for (Method method : methods) { if (method.isAnnotationPresent(YRequestMapping.class)) { methodUrl = method.getAnnotation(YRequestMapping.class).value(); String uri = "/" + baseUrl + "/" + methodUrl; //url method放入集合 handleMap.put(uri, method); } } } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } //获取对象名并把首字母转为小写 private String toLowerLetters(String simpleName) { String letters = simpleName.substring(0, 1).toLowerCase(); return letters + simpleName.substring(1); } }

配置tomcat启动访问http://localhost:8080/spring_war_exploded/item/query?name=zhangsan&id

最新回复(0)