MVC架构探究及其源码实现(3)-WebApplicationContext-阿里云开发者社区

开发者社区> james_zhan> 正文

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)-简单示例

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
VB源码之友升级了(系统内核的升级最近也要推出)
        以前有些懒,虽然用源码之友过程中出现了几次 VB IDE死机(害的要关闭VB IDE,如果没保存就惨了),不过一般免费用户遇不到,那是在专业版中提供的仅对函数内整理的功能。
597 0
+关注
james_zhan
全栈工程师,程序设计语言控
34
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载