P3插件式应用开发框架——初探
本帖最后由 mcl77361 于 2014-12-4 21:30 编辑一、开篇杂谈
接触“JEECG快速开发框架”已有一年有余,在此期间也使用该框架进行了两个系统的开发,个人感觉开发效率提高不少。上周有幸接触到P3插件式应用开发框架(以下简称P3),兴趣使然进行了一些研究和探索,在此抛砖引玉,留个印记。
二、WEB框架概述
P3作为一个Web开发框架,它的实现原理是什么,插件式设计思路又是如何呢?
首先,让我们来看看一个web请求的处理过程的简图。如图:web.png
从简图我们可以看出,基于Servlet容器的WEB框架实现有两种方式。一种通过实现Filter接口,另外一种实现Servlet。通过统一拦截浏览器的请求再分发给具体业务处理类,从而实现响应,产生HTML代码,返回给浏览器。如:Struts2.x/StrutsPrepareAndExecuteFilter(实现Filter接口)。SpringMVC/DispatcherServlet(实现Servlet)。
而P3是采用何种方式呢?实现Filter接口。有图有真相。P3Framework-filter.png
三、P3总体结构
P3是Filter实现的可扩展的插件式开发框架。
3.1 Filter实现是如何的?
该框架的核心引擎是实现Filter接口。如图:Framework-filter.png
在Filter初始化(init方法)中应用Spring对“应用配置文件”进行加载解析。
在Filter拦截方法(doFilter)中通过RequestProcess调度在“应用配置文件”注册进来的请求处理器进行请求的处理。请求处理器负责请求的解析和具体业务处理对象(如Action)的生成、调用和页面渲染。如图:requestProcess.png
3.2如何实现插件式扩展
是对2.1提到的请求处理器进行扩展,实现插件式注入。每个插件实现需实现请求处理器接口如图:process.png
3.3处理链逻辑如何
按注册“请求处理器”的顺序进行链条式调用,只有某个请求处理器认为完全处理,链条中断,不再往下传递。如:
for (Process handler : processHandlers) {
if (handler.execUrlPattern(url)) {
if (logger.isDebugEnabled())
logger.debug("\t" + handler.getClass().getName()+ " process");
if (handler.process(request, response)) {
if (logger.isDebugEnabled())
logger.debug("processChain finish");
return true;
}
}
}
3.4页面渲染如何处理?
public boolean process(HttpServletRequest request, HttpServletResponse response) throws IOException;
从“请求处理器”接口我们可以看出,页面渲染在处理器中通过response进行响应,具体应用如何渲染引擎如:freemarket/jsp/velocity,则由“请求处理器”具体实现者来承担(实现)。由此我们可以判断该框架是可以支持多种渲染引擎的。
四、“请求处理器”实现实例分析[ActionProcessHandler/ResourceProcessHandler]
所有的具体请求处理器都必须实现Process接口。该接口定义了以下方法。
(1) setUrlPattern(String urlPattern) //用于设置该请求处理器,要处理的url匹配规则,为外界设置提供入口。
(2) boolean execUrlPattern(StringBuffer url) //用于决定某个url请求是否能被该请求处理器处理(类似Mapping)。
(3) boolean process(HttpServletRequestrequest,HttpServletResponse response)//处理请求,返回true整个处理链中断。否则往下继续传递。
为了更便捷的实现该接口,框架提供了一个默认抽象类实现了(1)(2)。我们只需要继承该抽象类并实现process方法即可。
public abstract class ProcessHandler implementsProcess
4.1 ActionProcessHandler实现
public class ActionProcessHandler extends ProcessHandler
public boolean process(HttpServletRequestrequest,HttpServletResponse response) throws IOException {
returninvoke(request, response, UrlRole.parse(request));
} UrlRole.parse负责对请求的url进行解析得出具体的Action类的全限定名和方法,详细的解析逻辑请查看UrlRole类。 private invoke(HttpServletRequestrequest,HttpServletResponse response, UrlRole urlRole){ Class<?> actionClass = Class.forName(urlRole.getClassName()); AbstractActionaction = (AbstractAction)actionClass.newInstance(); Method actionMethod= actionClass.getMethod(urlRole.getMethodName()); action.request= request; action.response= response; Object rtn = actionMethod.invoke(action); booleanresult = true; if (rtn !=null) { result = outputToResponse(request, response,rtn.toString()); } returnresult; 从以上代码逻辑中不难看出,框架(根据解析出来的全限定类名和方法)采用反射机制实现方法的调用。 如在该请求处理器中实现具体业务处理Action类,需注意以下几点: (1)包名需满足以下规则:com.buss.xxx.yyy.action【详情请参考UrlRole类】 (2)响应的方法为无参方法。 (3)方法返回值为HTML代码或浏览器可接受的数据形式。 4.2 ResourceProcessHandler实现 实现静态资源的响应输出。 public boolean process(HttpServletRequestrequest, HttpServletResponse response) { try { String url = request.getRequestURI(); url =url.replaceFirst(request.getContextPath(), ""); InputStream is = this.getClass().getResourceAsStream("/content" +url); if (is != null) {zip(request,response,is);} 从红色标识部分我们可以看出要加载的静态资源必须在classpath下的content目录下。应用该请求处理同时还可达到压缩输 出的效果。五、框架中常用渲染引擎的初始化及应用
框架中对渲染引擎的支持以工具类的形式提供。即提供静态方法调用接口。每个渲染引擎工具类以实现InitializingBean接口已达到引擎初始化目的。具体分析如下:
5.1 Velocity
public class VelocityHelper implements InitializingBean
Velocity页面渲染引擎工具类,提供两个有用的接口,如下:
(1) public static String merge(String template, VelocityContext velocityContext)
(2) public static String merge(String template)
5.2 Freemarket
public class FreemarkerViewHelper implements InitializingBean
Freemarket页面渲染引擎工具类,提供多个有用的接口,如下:
(1) parseTemplate(String tplName, String encoding,Map<String, Object> paras)
(2) parseTemplate(String tplName, Map<String, Object> paras)
六、请求同步处理问题
框架中实现了对request、response对象的同步处理。
具体实现为: SynchronizationHelper。
框架中引入同步机制,是解决同一个请求在多个线程中处理的并发问题,还是预先设计,个人对该功能的设计思路不是很 清晰,希望有机会能和群主沟通交流。个人感觉此处引入同步机制,有一个优点。提供了一个便捷的手段在请求链上下文 中获取request、response对象。
框架实现同步的原理为:运用线程变量ThreadLocal实现。【注:一般的JDBC事务管理实现也是基于该机制实现】。
六、个人一点建议
(1) ActionProcessHandler中Action对象生成的优化
Class<?> actionClass = Class.forName(urlRole.getClassName());
框架中目前对Action对象的生成采用反射机制生成。无法实现Service层注入问题。
建议:使用SpringHelper.getBean实现Action对象的获取。(注:解析机制和bean的id需重新考虑和解析)
(2) ActionProcessHandler中无参方法的优化
框架中目前的响应方法都是无参方法,需要获取客户端传来的参数,只能通过
SynchronizationHelper.getCurrentRequest或AbstractAction.request。
建议:引入机制解决带参方法和参数的自动转型填充的问题。
(3)ResourceProcessHandler资源加载路径相对固定
该请求处理器加载的资源路径为:classpath下的content目录下资源。无法动态配置。
建议:提供接口设置加载路径,同时,引入URLClassloader加载指定路径下的资源。
页:
[1]