当前位置: 首页 > news >正文

水冶那里有做网站的专业建站推广网络公司

水冶那里有做网站的,专业建站推广网络公司,做企业网站的步骤,网站外链建设布局手动实现SpringMVC底层机制 博客的技术栈分析 #x1f6e0;️具体实现细节总结 #x1f41f;准备工作#x1f34d;搭建SpringMVC底层机制开发环境 实现任务阶段一#x1f34d;开发ZzwDispatcherServlet#x1f966;说明: 编写ZzwDispatcherServlet充当原生的DispatcherSer… 手动实现SpringMVC底层机制 博客的技术栈分析 ️具体实现细节总结 准备工作搭建SpringMVC底层机制开发环境 实现任务阶段一开发ZzwDispatcherServlet说明: 编写ZzwDispatcherServlet充当原生的DispatcherServlet(即核心控制器)分析代码实现配置Tomcat, 完成测试 实现任务阶段二完成客户端/浏览器可以请求控制层1.创建自己的Controller和自定义注解2.配置zzwspringmvc.xml3.编写XMLParser工具类, 可以解析zzwspringmvc.xml4.开发 ZzwWebApplicationContext, 充当Spring容器-得到扫描类的全路径列表.5.完善ZzwWebApplicationContext, 充当Spring容器-实例化对象到容器中6.完成请求URL和控制器方法的映射关系7.完成ZzwDispatcherServlet 分发请求到对应控制器方法 实现任务阶段三从web.xml动态获取zzwspringmvc.xml 实现任务阶段四完成自定义Service注解功能 ⬅️ 上一篇: SpringMVC系列六: 视图和视图解析器 欢迎来到 SpringMVC系列七: 手动实现SpringMVC底层机制-上 在本篇文章中我们将深入探讨如何手动实现SpringMVC的底层机制。通过理解这些机制可以更好地掌握SpringMVC的工作原理。 本篇需要用到的项目: zzw-springmvc项目 博客的技术栈分析 ️ 主要技术 前端框架: 无此博客主要关注于 SpringMVC 后端实现因此未涉及具体前端框架 后端框架: SpringMVC SpringMVC 是 Spring Framework 的一个模块用于构建基于 MVC (Model-View-Controller) 架构的 web 应用程序。博客中详细讲解了如何手动实现 SpringMVC 的核心机制包括前端控制器、请求处理流程等。 依赖管理: Maven Maven 是一个项目管理和构建工具用于管理项目依赖和构建流程。通过配置 pom.xml 文件来管理项目的依赖项如 Servlet API、Junit 等。 注解处理: 自定义注解 博客中使用了自定义注解如 Controller 和 RequestMapping来标识控制器类和方法并通过反射实现注解处理。 辅助工具 XML 配置: Dom4j Dom4j 是一个用于处理 XML 的开源 Java 库。博客中使用 Dom4j 解析 zzwspringmvc.xml 配置文件以获取需要扫描的包路径。 反射 API: Java 反射 Java 反射 API 被广泛用于动态获取类信息和调用方法。博客通过反射机制来扫描包、实例化类和调用控制器方法。 ️ 集合框架: ConcurrentHashMap 使用 ConcurrentHashMap 来存储 IoC 容器中的 bean 实例确保线程安全。 功能模块 核心控制器: ZzwDispatcherServlet 继承 HttpServlet 类通过覆盖 doGet 和 doPost 方法实现核心控制器功能处理所有请求并将其分发到对应的控制器方法。 自定义 IoC 容器: ZzwWebApplicationContext 模拟 Spring 的 IoC 容器扫描指定包路径下的类并将带有注解的类实例化并存储到容器中。 请求映射处理: ZzwHandler 维护 URL 与控制器方法的映射关系并在请求到达时根据 URL 查找并调用对应的控制器方法。 具体实现细节 核心控制器 (ZzwDispatcherServlet) 通过在 web.xml 中配置将所有请求映射到 ZzwDispatcherServlet实现统一的请求分发。 IoC 容器 (ZzwWebApplicationContext) 扫描指定包路径下的类判断是否包含特定注解如 Controller, Service并实例化这些类存储到 ConcurrentHashMap 中。 请求映射 (ZzwHandler) 使用自定义注解 RequestMapping 指定控制器方法的 URL 映射在请求到达时通过 URL 找到对应的控制器方法并调用。 反射机制 通过反射获取类的元数据和注解信息动态调用方法。 XML 解析 使用 Dom4j 解析 Spring 配置文件 zzwspringmvc.xml获取需要扫描的包路径实现配置的灵活性。 总结 本博客深入剖析了 SpringMVC 的底层实现机制通过手动实现类似 SpringMVC 的功能展示了 Java 反射、注解处理、XML 解析等技术的应用。通过这种方式读者能够更好地理解 SpringMVC 的工作原理提升自身的编程能力和框架理解能力。 准备工作 搭建SpringMVC底层机制开发环境 前提: 搭建maven环境 1.创建zzw-springmvc项目, 这是一个maven-web项目 出现了点小插曲. 项目建成后, 没有src目录, 且右下角报错 Cannot find JRE 1.7 做如下修改 改成1.8 缺少的文件夹需自己手动创建 pom.xml配置 dependenciesdependencygroupIdjunit/groupIdartifactIdjunit/artifactIdversion4.11/versionscopetest/scope/dependency!--引入原生servlet依赖的jar包--dependencygroupIdjavax.servlet/groupIdartifactIdjavax.servlet-api/artifactIdversion3.1.0/version!--解读1.scope标签表示引入的jar包的作用范围2.provided:表示该项目在打包, 放到生产环境时, 不需要带上servlet-api.jar包3.因为tomcat本身是有servlet的jar包, 到时直接使用tomcat本身的servlet-api.jar包, 防止版本冲突4.到后面会再次学习maven.--scopeprovided/scope/dependency!--引入dom4j--dependencygroupIddom4j/groupIdartifactIddom4j/artifactIdversion1.6.1/version/dependency!--引入常用工具类的jar包-该jar包含有很多常用的类--dependencygroupIdorg.apache.commons/groupIdartifactIdcommons-lang3/artifactIdversion3.5/version/dependency /dependencies实现任务阶段一 开发ZzwDispatcherServlet 说明: 编写ZzwDispatcherServlet充当原生的DispatcherServlet(即核心控制器) 分析代码实现 1.com.zzw.zzwspringmvc.servlet包下新建ZzwDispatcherServlet.java /*** 解读* 1.ZzwDispatcherServlet 充当原生的DispatcherServlet* 2.本质是一个Servlet, 继承HttpServlet*/ public class ZzwDispatcherServlet extends HttpServlet {Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req, resp);}Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println(ZzwDispatcherServlet doPost()...);} }2.src/main/resources(类路径)下新建 zzwspringmvc.xml, spring的容器配置文件 !--先空着--对应的类路径 3.webapp/WEB-INF配置web.xml load-on-startup讲解 !--配置ZzwDispatcherServlet, 作为我们自己的前端控制器-- servletservlet-nameZzwDispatcherServlet/servlet-nameservlet-classcom.zzw.zzwspringmvc.servlet.ZzwDispatcherServlet/servlet-class!--给ZzwDispatcherServlet配置参数, 指定要操作的spring容器配置文件--init-paramparam-namecontextConfigLocation/param-nameparam-valueclasspath:zzwspringmvc.xml/param-value/init-param!--ZzwDispatcherServlet在tomcat启动时, 就会自动加载. 调用init方法--load-on-startup1/load-on-startup /servlet servlet-mappingservlet-nameZzwDispatcherServlet/servlet-name!--因为ZzwDispatcherServlet作为前端控制器, 所以需要拦截所有请求--url-pattern//url-pattern /servlet-mapping配置Tomcat, 完成测试 1.配置tomcat 2.测试, 随便请求一个网址 实现任务阶段二 完成客户端/浏览器可以请求控制层 1.创建自己的Controller和自定义注解 示意图[分析说明] 1.在com.zzw.controller下新建MonsterController public class MonsterController {//编写方法, 可以列出怪物列表//springmvc 是支持原生的servlet api, 为了看到底层机制//这里我们涉及两个参数public void listMonster(HttpServletRequest request, HttpServletResponse response) {//设置返回编码和返回类型response.setContentType(text/html;charsetutf-8);//获取writer返回信息try {response.getWriter().write(h1妖怪名信息: 孙悟空--猪八戒--沙僧/h1);} catch (IOException e) {throw new RuntimeException(e);}} }2.在com.zzw.zzwspringmvc.annotation下新建注解类Controller RetentionPolicy.RUNTIME: 编译器把注解记录在class文件中, 当运行Java程序时, JVM 会保留注解. 程序可以通过反射获取该注解 /*** author 赵志伟* version 1.0* 该注解用于标识一个控制器组件* 这里涉及到注解知识, 在java基础*/ Target(ElementType.TYPE) Retention(RetentionPolicy.RUNTIME) Documented public interface Controller {String value() default ; }3.在该包下新建注解类RequestMapping /*** author 赵志伟* version 1.0* RequestMapping 注解用于指定控制器-方法的映射路径*/ Target(ElementType.METHOD) Retention(RetentionPolicy.RUNTIME) Documented public interface RequestMapping {String value() default ;; }4.在MonsterController中添加注解 Controller public class MonsterController {//编写方法, 可以列出怪物列表//springmvc 是支持原生的servlet api, 为了看到底层机制//这里我们涉及两个参数RequestMapping(value /monster/list)public void listMonster(HttpServletRequest request, HttpServletResponse response) {//设置返回编码和返回类型response.setContentType(text/html;charsetutf-8);//获取writer返回信息try {response.getWriter().write(h1妖怪名信息: 孙悟空--猪八戒--沙僧/h1);} catch (IOException e) {throw new RuntimeException(e);}} }2.配置zzwspringmvc.xml ?xml version1.0 encodingUTF-8 ? beans!--指定要扫描的基本包以及子包的java类-- component-scan base-packagecom.zzw.controller/ /beans3.编写XMLParser工具类, 可以解析zzwspringmvc.xml Dom4j解析配置文件代码实现 1.在com.zzw.zzwspringmvc.xml编写XMLParser工具类, 可以解析zzwspringmvc.xml, 得到要扫描的包 /*** author 赵志伟* version 1.0* XMLParser 用于解析spring配置文件*/ SuppressWarnings({all}) public class XMLParser {public static String getBasePackage(String xmlFile) {//1.得到解析器SAXReader reader new SAXReader();//2.得到类的加载路径 获取到spring配置文件[对应的资源流]InputStream inputStream XMLParser.class.getClassLoader().getResourceAsStream(xmlFile);try {//3.得到xml文件的文档Document document reader.read(inputStream);//4.获取rootElementElement rootElement document.getRootElement();//5.获取component-scan节点Element componentScanElement (Element) rootElement.elements(component-scan).get(0);//6.获取component-scan节点的base-package属性值String basePackage componentScanElement.attributeValue(base-package);//7.返回return basePackage;} catch (Exception e) {throw new RuntimeException(e);}} }2.在com.zzw.test新建ZzwSpringMVCTest.java测试类 XMLParser类在很多包下都有, 别选错 public class ZzwSpringMVCTest {Testpublic void readXML() {String basePackage XMLParser.getBasePackage(zzwspringmvc.xml);System.out.println(basePackage);} }4.开发 ZzwWebApplicationContext, 充当Spring容器-得到扫描类的全路径列表. 把指定的目录包括子目录下的java类的全路径扫描到集合中, 比如 ArrayList [java基础] 示意图[分析说明] 1.在com.zzw.zzwspringmvc.context下新建ZzwWebApplicationContext.java /*** author 赵志伟* version 1.0* ZzwWebApplicationContext 表示我们自己的spring容器*/ SuppressWarnings({all}) public class ZzwWebApplicationContext {//定义属性classFullPathList, 保存扫描包/子包的类的全路径private ListString classFullPathList new ArrayListString();//编写方法, 完成自己的spring容器的初始化public void init() {String basePackage XMLParser.getBasePackage(zzwspringmvc.xml);scanPackage(basePackage);}/*** 创建方法, 完成对包的扫描-涉及 io/容器/字符串处理* param pack 表示要扫描的包, 比如 com.zzw.controller*/public void scanPackage(String pack) {//通过类的加载器, 得到指定的包所在的工作路径对应的绝对路径//比如 com.zzw.controller url file:/D:/idea_project/zzw_springmvczzw-springmvc/target/classes/com/zzw/controllerClassLoader classLoader this.getClass().getClassLoader();URL url classLoader.getResource(pack.replace(., /));//细节说明:// 1.不要直接使用Junit测试, 否则 url返回null// 2.启动Tomcat测试, 才能得到这个类路径System.out.println(url url);} }2.前端控制器ZzwDispatcherServlet增加init方法 /*** 解读* 1.ZzwDispatcherServlet 充当原生的DispatcherServlet* 2.本质是一个Servlet, 继承HttpServlet*/ public class ZzwDispatcherServlet extends HttpServlet {Overridepublic void init(ServletConfig config) throws ServletException {super.init(config);ZzwWebApplicationContext zzwWebApplicationContext new ZzwWebApplicationContext();zzwWebApplicationContext.init();}Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req, resp);}Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println(ZzwDispatcherServlet doPost()...);} }3.启动Tomcat, 进行测试 4.开发自己的spring容器 /*** author 赵志伟* version 1.0* ZzwWebApplicationContext 表示我们自己的spring容器*/ SuppressWarnings({all}) public class ZzwWebApplicationContext {//定义属性classFullPathList, 保存扫描包/子包的类的全路径private ListString classFullPathList new ArrayListString();//编写方法, 完成自己的spring容器的初始化public void init() {String basePackage XMLParser.getBasePackage(zzwspringmvc.xml);scanPackage(basePackage);System.out.println(classFullPathList classFullPathList);}/*** 创建方法, 完成对包的扫描-涉及 io/容器/字符串处理** param pack 表示要扫描的包, 比如 com.zzw.controller*/public void scanPackage(String pack) {//通过类的加载器, 得到指定的包所在的工作路径对应的绝对路径//比如 com.zzw.controller url file:/D:/idea_project/zzw_springmvc/zzw-springmvc/target/zzw-springmvc/WEB-INF/classes/com/zzw/controller/ClassLoader classLoader this.getClass().getClassLoader();URL url classLoader.getResource(pack.replace(., /));//细节说明:// 1.不要直接使用Junit测试, 否则 url返回null// 2.启动Tomcat测试, 才能得到这个类路径System.out.println(url url);//根据得到的路径, 对其进行扫描, 把类的全路径保存到classFullPathListString path url.getFile();File dir new File(path);//在io中, 目录也是文件//遍历dir[文件/子目录]for (File f : dir.listFiles()) {if (f.isDirectory()) {//如果是一个目录, 需要递归扫描scanPackage(pack . f.getName());//f.getName() 子包的名称} else {//说明: 这时, 你扫描到的文件, 可能是.class文件, 也可以是其它文件// 就算是.class文件, 也存在是不是需要注入到容器中的问题// 目前先把所有.class文件的全路径都保存到集合中, 后面在注入对象到容器时, 再处理// 这里只考虑 .class文件String classFullPath pack . f.getName().replaceAll(.class, );classFullPathList.add(classFullPath);}}} }5.在com.zzw.controller.xx包下新建GoodsController, OrderController. 6.重启Tomcat, 测试 5.完善ZzwWebApplicationContext, 充当Spring容器-实例化对象到容器中 功能说明: 将扫描到的类, 在满足条件的情况下(即有相应的注解Controller Service...时), 反射到ioc容器. 1.ZzwWebApplicationContext 增加ioc属性. 增加executeInstance方法 /*** author 赵志伟* version 1.0* ZzwWebApplicationContext 表示我们自己的spring容器*/ SuppressWarnings({all}) public class ZzwWebApplicationContext {//定义属性ioc, 存放反射生成的bean对象public ConcurrentHashMapString, Object ioc new ConcurrentHashMapString, Object();//编写方法, 完成自己的spring容器的初始化public void init() {String basePackage XMLParser.getBasePackage(zzwspringmvc.xml);scanPackage(basePackage);System.out.println(classFullPathList classFullPathList);//将扫描到的类, 反射到ioc容器executeInstance();System.out.println(扫描后的 ioc容器 ioc);}//编写方法, 将扫描到的类, 在满足条件的情况下, 反射到ioc容器public void executeInstance() {//判断是否扫描到类if (classFullPathList.size() 0) {//说明没有扫描到类return;}try {//遍历classFullPathList, 进行反射for (String classFullPath : classFullPathList) {Class? clazz Class.forName(classFullPath);//说明当前这个类有Controllerif (clazz.isAnnotationPresent(Controller.class)) {//beanName 假设是默认的, 即类名首字母小写String beanName clazz.getSimpleName().substring(0, 1).toLowerCase() clazz.getSimpleName().substring(1);ioc.put(beanName, clazz.newInstance());}//如果有其它注解, 可以拓展!!}} catch (Exception e) {throw new RuntimeException(e);}} }我这里输出的时候乱码, 我的解决方案是. 全改成UTF-8 测试 6.完成请求URL和控制器方法的映射关系 功能说明: 将配置的RequestMapping的url和 对应的 控制器-方法 映射关系保存到集合中 示意图[分析说明] 1.在com.zzw.zzwspringmvc.handler下新建ZzwHandler /*** author 赵志伟* version 1.0* ZzwHandler 对象记录请求的url 和 控制器方法映射关系*/ SuppressWarnings({all}) public class ZzwHandler {private String url;private Object controller;private Method method;public ZzwHandler(String url, Object controller, Method method) {this.url url;this.controller controller;this.method method;}//getter, setter, toString方法 }2.修改ZzwDispatcherServlet 将init方法内声明的zzwWebApplicationContext属性提到外面, 扩大它的作用域定义属性 handlerList, 保存ZzwHandler[url 和 控制器-方法的映射关系]编写方法[initHandlerMapping], 完成url 和 控制器-方法的映射 (initHandlerMapping也可以写在HandlerMapping类中, 逻辑是一样的) /*** 解读* 1.ZzwDispatcherServlet 充当原生的DispatcherServlet* 2.本质是一个Servlet, 继承HttpServlet* 3.提示: 这里我们需要使用到 java web 讲解的Servlet*/ public class ZzwDispatcherServlet extends HttpServlet {//定义属性 handlerList, 保存ZzwHandler[url 和 控制器-方法的映射关系]private ListZzwHandler handlerList new ArrayListZzwHandler();//定义属性 zzwWebApplicationContext, 自己的spring容器ZzwWebApplicationContext zzwWebApplicationContext null;Overridepublic void init(ServletConfig config) throws ServletException {super.init(config);zzwWebApplicationContext new ZzwWebApplicationContext();zzwWebApplicationContext.init();//调用 initHandlerMapping, 完成url和控制器方法的映射initHandlerMapping();System.out.println(handlerList初始化的结果 handlerList);}Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req, resp);}Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println(ZzwDispatcherServlet doPost()...);}//编写方法, 完成url 和 控制器方法的映射private void initHandlerMapping() {if (zzwWebApplicationContext.ioc.isEmpty()) {//判断当前的ioc容器是否为空return;}//遍历ioc容器的bean对象, 然后进行url映射处理//java基础 map遍历for (Map.EntryString, Object entry : zzwWebApplicationContext.ioc.entrySet()) {//先取出实例, 转化为clazz对象[要获取类的内部信息, 类的实例对象不好用, 要用类的Class对象 反射知识]Class? clazz entry.getValue().getClass();//如果注入的bean是Controllerif (clazz.isAnnotationPresent(Controller.class)) {//取出它所有的方法Method[] declaredMethods clazz.getDeclaredMethods();//遍历方法for (Method declaredMethod : declaredMethods) {//判断该方法是否有RequestMappingif (declaredMethod.isAnnotationPresent(RequestMapping.class)) {//取出RequestMapping值 - 就是映射路径RequestMapping requestMappingAnnotation declaredMethod.getDeclaredAnnotation(RequestMapping.class);String url requestMappingAnnotation.value();//创建ZzwHandler对象-就是一个映射关系 [保存映射关系]ZzwHandler zzwHandler new ZzwHandler(url, entry.getValue(), declaredMethod);//放入到 handlerListhandlerList.add(zzwHandler);}}}}} }7.完成ZzwDispatcherServlet 分发请求到对应控制器方法 功能说明: 完成ZzwDispatcherServlet 分发请求到对应控制器方法 示意图[分析说明] -当用户发出请求, 根据用户请求url 找到对应的 控制器-方法, 并反射调用 -如果用户请求的路径不存在, 返回404 1.ZzwDispatcherServlet添加getZzwHandler()方法和executeDispatcher()方法, 在doPost中调用 executeDispatcher()方法 public class ZzwDispatcherServlet extends HttpServlet {Overridepublic void init(ServletConfig config) throws ServletException {super.init(config);//创建自己的spring容器zzwWebApplicationContext new ZzwWebApplicationContext();zzwWebApplicationContext.init();//调用 initHandlerMapping, 完成url和控制器方法的映射initHandlerMapping();System.out.println(handlerList初始化的结果 handlerList);}Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req, resp);}Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//System.out.println(ZzwDispatcherServlet doPost()...);//调用方法, 完成请求转发executeDispatcher(req, resp);}//编写方法, 通过request对象, 返回ZzwHandler对象//如果没有, 就返回nullprivate ZzwHandler getZzwHandler(HttpServletRequest request) {//1.先获取到用户请求的url 比如http://localhost:8080/zzw_springmvc/monster/list// uri /zzw_springmvc/monster/list//2.这里要注意得到的uri 和 保存的url 有一个工程路径的问题//两个方案解决 第一个方案: 简单 tomcat 直接配置 application context /// 第二个方案: 保存 zzwHandler对象的url时, 拼接 this.getServletContext().getContextPath()String requestURI request.getRequestURI();//遍历 handlerListfor (ZzwHandler zzwHandler : handlerList) {if (requestURI.equals(zzwHandler.getUrl())) {//说明匹配成功return zzwHandler;}}return null;}//编写方法, 完成分发请求任务private void executeDispatcher(HttpServletRequest request,HttpServletResponse response) {try {ZzwHandler zzwHandler getZzwHandler(request);if (zzwHandler null) {//说明用户请求的路径/资源不存在response.getWriter().print(h1404 NOT FOUND!/h1);} else {//匹配成功, 反射调用控制器的方法zzwHandler.getMethod().invoke(zzwHandler.getController(), request, response);}} catch (Exception e) {throw new RuntimeException(e);}} }2.OrderController增加两个方法listOrder(), addOrder() 别忘了加Controller注解 Controller public class OrderController {RequestMapping(value /order/list)public void listOrder(HttpServletRequest request, HttpServletResponse response) {//设置返回编码和返回类型response.setContentType(text/html;charsetutf8);//获取writer返回信息try {response.getWriter().write(h1订单列表信息/h1);} catch (IOException e) {throw new RuntimeException(e);}}RequestMapping(value /order/add)public void addOrder(HttpServletRequest request, HttpServletResponse response) {//设置返回编码和返回类型response.setContentType(text/html;charsetutf8);//获取writer返回信息try {response.getWriter().write(h1添加订单信息/h1);} catch (IOException e) {throw new RuntimeException(e);}} }3.GoodsController增加一个方法listGoods() Controller public class GoodsController {RequestMapping(value /goods/list)public void listGoods(HttpServletRequest request, HttpServletResponse response) {//设置返回编码和返回类型response.setContentType(text/html;charsetutf8);//获取writer返回信息try {response.getWriter().write(h1商品列表信息.../h1);} catch (IOException e) {throw new RuntimeException(e);}} }4.测试(注意: 不要再加工程路径了) handlerList初始化的结果 [ZzwHandler{url‘/goods/list’, controllercom.zzw.controller.xx.GoodsController79b1752f, methodpublic void com.zzw.controller.xx.GoodsController.listGoods(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)},   ZzwHandler{url‘/order/add’, controllercom.zzw.controller.xx.OrderController1b82cb63, methodpublic void com.zzw.controller.xx.OrderController.addOrder(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)},   ZzwHandler{url‘/order/list’, controllercom.zzw.controller.xx.OrderController1b82cb63, methodpublic void com.zzw.controller.xx.OrderController.listOrder(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)},   ZzwHandler{url‘/monster/list’, controllercom.zzw.controller.MonsterController32128628, methodpublic void com.zzw.controller.MonsterController.listMonster(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)}] 实现任务阶段三 从web.xml动态获取zzwspringmvc.xml 说明: 前面我们加载zzwspringmvc.xml是硬编码, 现在做活. 从web.xml动态获取 示意图[分析说明] 1.ZzwDispatcherServlet在创建并初始化ZzwWebApplicationContext时, 动态地从web.xml中获取到spring配置文件. servletConfig使用 /*** 解读* 1.ZzwDispatcherServlet 充当原生的DispatcherServlet* 2.本质是一个Servlet, 继承HttpServlet* 3.提示: 这里我们需要使用到 java web 讲解的Servlet*/ public class ZzwDispatcherServlet extends HttpServlet {Overridepublic void init(ServletConfig servletConfig) throws ServletException {//获取到web.xml中的/*init-paramparam-namecontextConfigLocation/param-nameparam-valueclasspath:zzwspringmvc.xml/param-value/init-param*/String configLocation servletConfig.getInitParameter(contextConfigLocation);//创建自己的spring容器zzwWebApplicationContext new ZzwWebApplicationContext(configLocation);zzwWebApplicationContext.init();//调用 initHandlerMapping, 完成url和控制器方法的映射initHandlerMapping();System.out.println(handlerList初始化的结果 handlerList);}....... }2.ZzwWebApplicationContext.java中添加一个属性configLocation, 和一个无参构造器, 一个有参构造器, 并修改init()方法 /*** author 赵志伟* version 1.0* ZzwWebApplicationContext 表示我们自己的spring容器*/ public class ZzwWebApplicationContext {//定义属性classFullPath, 保存扫描包/子包的类的全路径private ListString classFullPathList new ArrayListString();//定义属性ioc, 存放反射生成的bean对象 有Controller/Service注解public ConcurrentHashMapString, Object ioc new ConcurrentHashMapString, Object();//创建一个属性, 表示spring容器配置文件private String configLocation; //添加一个无参构造器public ZzwWebApplicationContext() {}//构建一个有参构造器public ZzwWebApplicationContext(String configLocation) {this.configLocation configLocation;}//编写方法, 完成自己的spring容器的初始化public void init() {//这里我们写的是固定的spring容器配置文件 做活//String basePackage XMLParser.getBasePackage(zzwspringmvc.xml);String basePackage XMLParser.getBasePackage(configLocation.split(:)[1]);scanPackage(basePackage);System.out.println(basePackage basePackage);System.out.println(classFullPathList classFullPathList);//将扫描到的类, 反射到ioc容器executeInstance();System.out.println(扫描后的 ioc容器 ioc);}........ }3.测试… 实现任务阶段四 完成自定义Service注解功能 说明: 如果给某个类加上Service, 则可以将其注入到我们的Spring容器 示意图[分析说明] 补充: DAO和DB由MyBatis接管, 和SpringMVC关系并不大. 所以我们暂时不考虑DAO和DB. 1.在com.zzw.entity包下新建Monster public class Monster {private Integer id;private String name;private String skill;private Integer age;//全参构造器, getter, setter, toString方法 }2.在com.zzw.zzwspringmvc.annotation下新建Service. 这个注解是springmvc框架要支持的东西, 所以要在zzwspringmvc包下 /*** author 赵志伟* version 1.0* Service 注解, 用于标识一个Service对象, 并注入到spring容器*/ Target(ElementType.TYPE) Retention(RetentionPolicy.RUNTIME) Documented public interface Service {String value() default ; } 3.在com.zzw.service下新建MonsterService接口. public interface MonsterService {//增加方法-返回monster列表public ListMonster listMonster(); }3.1在com.zzw.service.impl新建MonsterServiceImpl实现类. 并标注Service, 表示可以将对象注入到Spring容器 /*** author 赵志伟* version 1.0* MonsterServiceImpl 作为一个Service注入到spring容器*/ SuppressWarnings({all}) public class MonsterServiceImpl implements MonsterService {//这里我们模拟数据-DBpublic ListMonster listMonster() {ListMonster monsters new ArrayListMonster();monsters.add(new Monster(100, 牛魔王, 芭蕉扇, 400));monsters.add(new Monster(200, 汤姆猫, 抓老鼠, 200));return monsters;} }3.2完善zzwspringmvc.xml , 加上com.zzw.service ?xml version1.0 encodingUTF-8 ? beans!--指定要扫描的基本包以及子包的java类-- component-scan base-packagecom.zzw.controller,com.zzw.service/ /beans3.3更改ZzwWebApplicationContext.java的init() //编写方法, 完成自己的spring容器的初始化public void init() {//这里我们写的是固定的spring容器配置文件 做活//String basePackage XMLParser.getBasePackage(zzwspringmvc.xml);String basePackage XMLParser.getBasePackage(configLocation.split(:)[1]);//这时我们的basePackage com.zzw.controller,com.zzw.service//scanPackage(basePackage);String[] basePackages basePackage.split(,);if (basePackages.length 0) {for (String pack : basePackages) {scanPackage(pack);}}........}4.ZzwWebApplicationContext的executeInstance增加一个else if分支. 并可以通过接口支持多级-类名来获取到Service Bean //编写方法, 将扫描到的类, 在满足条件的情况下, 反射到ioc容器 public void executeInstance() {//判断是否扫描到类if (classFullPathList.size() 0) {//说明没有扫描到类return;}try {//遍历classFullPathList, 进行反射for (String classFullPath : classFullPathList) {Class? clazz Class.forName(classFullPath);//说明当前这个类有Controller注解if (clazz.isAnnotationPresent(Controller.class)) {//beanName 假设是默认的, 即类名首字母小写String beanName clazz.getSimpleName().substring(0, 1).toLowerCase() clazz.getSimpleName().substring(1);ioc.put(beanName, clazz.newInstance());}//如果有其它注解, 可以拓展!! 处理Serviceelse if (clazz.isAnnotationPresent(Service.class)) {//如果类有Service//先获取到Service的value值 就是注入时的beanNameService serviceAnnotation clazz.getDeclaredAnnotation(Service.class);String beanName serviceAnnotation.value();if (.equals(beanName)) {//说明没有指定value, 我们就使用默认的机制注入Service//可以通过 接口名/类名[首字母小写] 来注入ioc容器//1.得到所有接口的名称接口Class?[] interfaces clazz.getInterfaces();Object instance clazz.newInstance();//2.遍历接口, 然后通过多个接口名来注入for (Class? anInterface : interfaces) {//接口名-首字母小写String beanName2 anInterface.getSimpleName().substring(0, 1).toLowerCase() anInterface.getSimpleName().substring(1);ioc.put(beanName2, instance);}//3.这里老师给留了个作业: 使用类名的首字母小写来注入bean// 通过 clazz 来获取即可.String beanName2 clazz.getSimpleName().substring(0, 1).toLowerCase() clazz.getSimpleName().substring(1);ioc.put(beanName2, instance);} else {//如果有指定名称, 就使用该名称注入即可ioc.put(beanName, clazz.newInstance());}}}} catch (Exception e) {throw new RuntimeException(e);} }5.测试-重启tomcat 扫描后的 ioc容器{goodsControllercom.zzw.controller.xx.GoodsController5fb9a20e,                               monsterServicecom.zzw.service.impl.MonsterServiceImpl3b03f989,                               monsterServiceImplcom.zzw.service.impl.MonsterServiceImpl3b03f989,                               orderControllercom.zzw.controller.xx.OrderController2f51e8b1,                               monsterControllercom.zzw.controller.MonsterController7a223f3b} 下一篇预告 敬请期待SpringMVC系列八: 手动实现SpringMVC底层机制-下 目录导航 SpringMVC系列一: 初识SpringMVCSpringMVC系列二: 请求方式介绍SpringMVC系列三: Postman(接口测试工具)SpringMVC系列四: Rest-优雅的url请求风格SpringMVC系列五: SpringMVC映射请求数据SpringMVC系列六: 视图和视图解析器SpringMVC系列七: 手动实现SpringMVC底层机制-上SpringMVC系列八: 手动实现SpringMVC底层机制-下 … 读者互动 在学习SpringMVC底层机制的过程中你有哪些疑问或需要帮助的地方欢迎在评论区留言我们一起讨论。
http://www.hkea.cn/news/14295094/

相关文章:

  • wordpress多格式视频播放插件seo发展现状
  • 免费网站建百度发布信息的免费平台
  • 网站建设售后回访话术秦皇岛建设银行网点分布
  • 山东天齐建设集团网站哈尔滨市建设工程交易中心网站
  • 网站忘记备案微信手机官方网站首页
  • 惠州建设局网站做网站需要几个岗位
  • 免费cms建站五指廊坊网络推广优化公司
  • 正能量网站入口免费安全哈尔滨专业网站营销
  • 我自己的网站怎么做关键词优化哪些网站可以做邀请函
  • 河北做网站的天津公司网站推广
  • 开发网站比较好的公司安阳网站建设
  • 网站设计欣赏移动黄骅港务公司
  • jq动画效果网站湘潭网站建设方案表格
  • 网站死链接检查wordpress插件统计
  • 刷题网站开发网站建立使用方法
  • 做的好的响应式网站wordpress 全局js
  • 手机建网站 优帮云软件开发自学需要
  • 网站建设cz35湖南网站设计亮点
  • 网站编程技术 吉林出版集团股份有限公司专注网站建设微信开发
  • 南宁彩票网站开发中山做网站公司
  • 站长工具seo诊断中小型网站建设
  • 建立网站需要做什么申请网站建设经费
  • 北京 科技网站建设wordpress用户上传视频教程
  • seo网站建设费用常德网站建设套餐报价
  • 兴国做网站wordpress分类模版
  • 滨州网站设计wordpress 加载图片
  • 北京专业网站建设公司排名企业网属于什么网
  • 网站市场做烂了100到300万企业所得税
  • 网站显示时间代码石家庄做企业网站最好的公司
  • 企业网站建设带后台网站设计流程