MVC架构探究及其源码实现(3)-WebApplicationContext

简介:

博学,切问,近思--詹子知 (https://jameszhan.github.io)

直接利用web.xml去配置和定义我们的对象组件显然是不灵活和不方便扩展的,由于我们系统中将会需要配置很多个不同的对象资源,比如控制器,View对象,HandlerMapping对象等等,如何对它们进行管理,如何能让我们的前端控制器访问和利用到到它们便是我们不得不面对的问题。还好,现在有了Spring,现在很多流行的MVC框架都支持使用Spring对自己容器里的对象资源进行管理。尽管Spring千好万好,我们这里还是决定不使用它,而是自己来写一个对象容器来管理我们的相关资源,这样我们不仅可以了解对象资源配置管理的细节,还可以顺带学习一下Spring等IOC容器的实现原理。当然,我们这里的实现方案将会尽可能的简单。
如下便是我们的WebApplicationContext类的实现,它能够自动查找WEB-INF路径下所有以config结尾的xml文件,并把其中定义的对象抽取出来,放到Application作用域中,由于我们这里只是个Sample,不需要考虑太多的并发的情况,所有对象的类型,我们都是用Singleton,也就是定义的每个对象都为所有的请求和Servlet共享。 WebApplicationContext中还定义了一个很有用的方法,beansOfType(Class<T>),该方法用于查找出系统中定义的所有的属于当前类型的所有对象资源。package com.google.mvc.web.context; import java.io.InputStream; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import javax.servlet.ServletContext; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.log4j.Logger; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; public class WebApplicationContext { private static final Logger LOGGER = Logger.getLogger(WebApplicationContext.class); private static final String WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".CONTEXT"; private Map<String, Object> cacheMap; private ServletContext servletContext; private DocumentBuilder builder; public WebApplicationContext(ServletContext servletContext) { this.servletContext = servletContext; DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); try { builder = factory.newDocumentBuilder(); } catch (ParserConfigurationException e) { LOGGER.error("Can't load dom builder", e); } } public void init() { ServletContext context = getServletContext(); Set<?> set = context.getResourcePaths("/WEB-INF"); Object map = servletContext.getAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE); if (map != null) { cacheMap = (Map<String, Object>) map; } else { cacheMap = new ConcurrentHashMap<String, Object>(); servletContext.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, cacheMap); for (Object o : set) { String path = (String) o; if (path.endsWith("config.xml")) { try { loadResource(servletContext.getResourceAsStream(path)); } catch (Exception ex) { LOGGER.error("Can't load resource " + path); } } } } } private void loadResource(InputStream resource) throws Exception{ Document doc = builder.parse(resource); Element root = doc.getDocumentElement(); NodeList nodeList = root.getElementsByTagName("bean"); for(int i = 0; i < nodeList.getLength(); i++){ Element el = (Element)nodeList.item(i); String id = el.getAttribute("id"); String className = el.getAttribute("class"); Class<?> clazz = this.getClass().getClassLoader().loadClass(className); Object o = createBean(id, clazz); NodeList propertyList = el.getElementsByTagName("property"); for(int j = 0; j < propertyList.getLength(); j++){ Element prop = (Element)propertyList.item(j); String methodName = getMethodName(prop.getAttribute("name")); Method m = clazz.getMethod(methodName, String.class); String property = prop.getAttribute("value"); Object dependObject = cacheMap.get(property); if(dependObject != null){ m.invoke(o, dependObject); } else { m.invoke(o, property); } } cacheMap.put(id, o); } } protected String getMethodName(String methodName){ StringBuilder sb = new StringBuilder(); sb.append("set"); sb.append(methodName.substring(0, 1).toUpperCase(Locale.US)); sb.append(methodName.substring(1)); return sb.toString(); } public Object createBean(Class<?> clazz) throws Exception{ return createBean(clazz.getCanonicalName(), clazz); } public Object createBean(String name, Class<?> clazz) throws Exception{ Object o = cacheMap.get(name); if(o == null){ o = clazz.newInstance(); if(o instanceof WebApplicationContextAware){ ((WebApplicationContextAware)o).setWebApplicationContext(this); } cacheMap.put(name, o); } LOGGER.info(name + "=" + clazz.getCanonicalName()); return o; } public Object getBean(String beanName){ return servletContext.getAttribute(beanName); } public ServletContext getServletContext() { return servletContext; } public void setServletContext(ServletContext servletContext) { this.servletContext = servletContext; } public <T> Map<String, T> beansOfType(Class<T> clazz){ Map<String, T> map = new HashMap<String, T>(); for(String key : cacheMap.keySet()){ Object o = cacheMap.get(key); if(clazz.isAssignableFrom(o.getClass())){ map.put(key, (T)o); } } return map; } } 我们再来看一下*.config.xml文件里对象资源的定义示例:<?xml version="1.0" encoding="UTF-8"?> <beans> <bean id="ControllerAdapter" class="com.google.mvc.web.servlet.mvc.ControllerHandlerAdapter" /> <bean id="HttpRequestAdapter" class="com.google.mvc.web.servlet.mvc.HttpRequestHandlerAdapter" /> <bean id="ViewResolver" class="com.google.mvc.web.servlet.mvc.DefaultViewResolver"> <property name="viewClass" value="com.google.mvc.web.servlet.mvc.InternalResourceView"/> <property name="prefix" value="/WEB-INF/"/> <property name="suffix" value=".jsp"/> </bean> <bean id="login.do" class="com.google.mvc.web.sample.LoginController" /> <bean id="hello.do" class="com.google.mvc.web.sample.HelloController" /> <bean id="404" class="com.google.mvc.web.servlet.mvc.HandlerFor404" /> </beans> 如果哪个对象资源需要在运行过程中使用到WebApplicationContext的资源及方法,只需实现接口WebApplicationContextAware即可,一旦实现了该接口,当前的WebApplicationContext会被自动的注入到此对象资源中。package com.google.mvc.web.context; public interface WebApplicationContextAware { void setWebApplicationContext(WebApplicationContext wac); }

相关文章:

  1. MVC架构探究及其源码实现(1)-理论基础
  2. MVC架构探究及其源码实现(2)-核心组件定义
  3. MVC架构探究及其源码实现(4)-前端控制器
  4. MVC架构探究及其源码实现(5)-相关组件实现
  5. MVC架构探究及其源码实现(6)-简单示例

目录
相关文章
|
6月前
|
人工智能 安全 Java
智慧工地源码,Java语言开发,微服务架构,支持分布式和集群部署,多端覆盖
智慧工地是“互联网+建筑工地”的创新模式,基于物联网、移动互联网、BIM、大数据、人工智能等技术,实现对施工现场人员、设备、材料、安全等环节的智能化管理。其解决方案涵盖数据大屏、移动APP和PC管理端,采用高性能Java微服务架构,支持分布式与集群部署,结合Redis、消息队列等技术确保系统稳定高效。通过大数据驱动决策、物联网实时监测预警及AI智能视频监控,消除数据孤岛,提升项目可控性与安全性。智慧工地提供专家级远程管理服务,助力施工质量和安全管理升级,同时依托可扩展平台、多端应用和丰富设备接口,满足多样化需求,推动建筑行业数字化转型。
204 5
|
3月前
|
运维 安全 数据可视化
采用PHP+Vue技术架构的不良事件管理系统(源码)
本系统为医院安全(不良)事件管理工具,支持快速上报、流程化处理与多维度分析,助力识别风险、优化管理。采用PHP+Vue技术架构,功能涵盖事件上报、追踪整改、数据统计及PDCA改进等。
121 0
|
12月前
|
JSON JavaScript 前端开发
Vue3源码架构简析及Monorepo流程构建
【10月更文挑战第12天】Vue3源码架构简析及Monorepo流程构建
Vue3源码架构简析及Monorepo流程构建
|
11月前
|
存储 前端开发 调度
Flux 与传统的 MVC 架构模式区别
Flux是一种用于构建用户界面的架构模式,与传统的MVC架构不同,它采用单向数据流,通过Dispatcher统一管理数据的分发,Store负责存储数据和业务逻辑,View只负责展示数据,使得应用状态更加可预测和易于维护。
|
7月前
|
运维 供应链 前端开发
中小医院云HIS系统源码,系统融合HIS与EMR功能,采用B/S架构与SaaS模式,快速交付并简化运维
这是一套专为中小医院和乡镇卫生院设计的云HIS系统源码,基于云端部署,采用B/S架构与SaaS模式,快速交付并简化运维。系统融合HIS与EMR功能,涵盖门诊挂号、预约管理、一体化电子病历、医生护士工作站、收费财务、药品进销存及统计分析等模块。技术栈包括前端Angular+Nginx,后端Java+Spring系列框架,数据库使用MySQL+MyCat。该系统实现患者管理、医嘱处理、费用结算、药品管控等核心业务全流程数字化,助力医疗机构提升效率和服务质量。
364 4
|
7月前
|
人工智能 前端开发 Java
DDD四层架构和MVC三层架构的个人理解和学习笔记
领域驱动设计(DDD)是一种以业务为核心的设计方法,与传统MVC架构不同,DDD将业务逻辑拆分为应用层和领域层,更关注业务领域而非数据库设计。其四层架构包括:Interface(接口层)、Application(应用层)、Domain(领域层)和Infrastructure(基础层)。各层职责分明,避免跨层调用,确保业务逻辑清晰。代码实现中,通过DTO、Entity、DO等对象的转换,结合ProtoBuf协议,完成请求与响应的处理流程。为提高复用性,实际项目中可增加Common层存放公共依赖。DDD强调从业务出发设计软件,适应复杂业务场景,是微服务架构的重要设计思想。
|
7月前
|
消息中间件 安全 NoSQL
布谷直播系统源码开发实战:从架构设计到性能优化
作为山东布谷科技的一名技术研发人员,我参与了多个直播系统平台从0到1的开发和搭建,也见证了直播行业从萌芽到爆发的全过程。今天,我想从研发角度,分享一些直播系统软件开发的经验和心得,希望能对大家有所帮助。
|
9月前
|
监控 JavaScript 数据可视化
建筑施工一体化信息管理平台源码,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
智慧工地云平台是专为建筑施工领域打造的一体化信息管理平台,利用大数据、云计算、物联网等技术,实现施工区域各系统数据汇总与可视化管理。平台涵盖人员、设备、物料、环境等关键因素的实时监控与数据分析,提供远程指挥、决策支持等功能,提升工作效率,促进产业信息化发展。系统由PC端、APP移动端及项目、监管、数据屏三大平台组成,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
316 7
|
10月前
|
机器学习/深度学习 前端开发 算法
婚恋交友系统平台 相亲交友平台系统 婚恋交友系统APP 婚恋系统源码 婚恋交友平台开发流程 婚恋交友系统架构设计 婚恋交友系统前端/后端开发 婚恋交友系统匹配推荐算法优化
婚恋交友系统平台通过线上互动帮助单身男女找到合适伴侣,提供用户注册、个人资料填写、匹配推荐、实时聊天、社区互动等功能。开发流程包括需求分析、技术选型、系统架构设计、功能实现、测试优化和上线运维。匹配推荐算法优化是核心,通过用户行为数据分析和机器学习提高匹配准确性。
674 5
|
设计模式 Java 关系型数据库
【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析
本文是“Java学习路线”专栏的导航文章,目标是为Java初学者和初中高级工程师提供一套完整的Java学习路线。
809 37

热门文章

最新文章