<h1>前言</h1> <p>java web的MVC,一个烂的不能再烂的一个话题了,能够说,如今市面上或者网上一搜,都有不少很优秀的MVC框架。那么这里为何还要写一篇着相关的文章呢,在这介绍下本文的背景,以前帮一个朋友作个网站,因为本人只会java,因此就用java写了一个,可是因为资金有限,只能找一些便宜的jsp空间,那么这样随之而来的问题就是,这样的空间实在是给的东西有限,最主要的问题就是内存不够。因此就想,若是我不用任何框架,纯servlet编写,是否就能节约内存和提升执行效率,因而选择了直接采用servlet编写,可是这样确实带来不少维护和编程上的不便。因而就想可否写一个MVC框架,在程序执行以前按照规则自动生成各类代理类,那么在程序运行的时候就不须要什么反射,注入等等。既然目标已经肯定,那么就按照这个思路继续往下走吧,就是如何按照规则自动生成咱们想要的class。</p> <h1>Action规则制定</h1> <p>首先咱们但愿定义Action的规则,他的主要做用就是告诉程序,不一样的请求是由哪些类和方法处理的。看看下面的代码: </p> <pre style="overflow: auto" class="brush:java;gutter:true;first-line:1;tab-size:4;toolbar:true;">代码1: @Action("/MockServlet") public class MockServletAction {java
@UrlMapping( value="/execute.action", method="GET", result="SUCCESS", path="/servlet/test.jsp" ) public String execute() throws IOException { return "SUCCESS"; }
}</pre>web
<p>这段代码很容易读懂,@Action注解告诉程序,全部以/MockServlet开头的请求由这个类处理,而@UrlMapping中的value告诉程序在/MockServlet以后又是"/execute.action"由execute()这个方法处理,而且必须是GET方式发送过来的请求;到到目前位置,这些注解有点Spring Mvc的味道了,接下来就是@UrlMapping的result和path属性了,其实他的意思就是当这个方法返回的是SUCCESS的时候采用"/servlet/test.jsp" 这个页面作图片的渲染。</p>编程
<p>接下来就是如何生成咱们想要的代码了,首先让咱们使用最原始的Servlet实现上面的功能,假设咱们的Action没有任何注解,代码以下: </p>app
<pre style="overflow: auto" class="brush:java;gutter:true;first-line:1;tab-size:4;toolbar:true;">代码2: public class MockServletAction { public String execute() throws IOException { return "SUCCESS"; } }</pre>框架
<p>咱们一样想让这个Action去处理/MockServlet/execute.action这个GET请求,那么咱们应该按照以下代码作:</p>jsp
<pre style="overflow: auto" class="brush:java;gutter:true;first-line:1;tab-size:4;toolbar:true;">代码3: public class ActionServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String servletPath = req.getServletPath(); if(servletPath.equals("/MockServlet/execute.action")){ String result = new MockServletAction().execute(); if(result.equals("SUCCESS")){ req.getRequestDispatcher("/servlet/test.jsp").forward(request, response); } } } }</pre>maven
<p>经过上面就可以明白,咱们但愿有这么一个框架,它可以经过代码1中的注解的中所定义的请求转发规则来自定生成代码3。这样就既可以高效率的运行,减小系统运行时资源的损耗,同时也也能提升开发效率。 </p>ide
<p>咱们也能够为事务作自动修改class,无非就是在方法先后加入事务启动和事务提交的代码;依赖注入的话就在构造方法中生成注入的代码等等. </p>svn
<h1>Class自动生成的策略</h1>网站
<p>有人也有疑问,就是我自动生成class,一样也是消耗资源的。没错不只仅消耗资源,并且还消耗的很是多。可是这种消耗是一次性的,也就是说我程序运行开始就将class生成好,之后就直接使用这个class而无需重复生成。可是有的时候server的配置实在太烂,或者我就是个极端主义者,我就是但愿server损耗的越少越好。那么为此这个就有如下两种策略供选择: </p>
<h2>1.运行时自动生成Class </h2>
<p>程序运行开始将全部须要的class自动生成或者将修改后的class替换成原有的class。固然这种方式的优势就是开发阶段快,可是弊端就是,咱们没法在server中替换已经load的class,而且大多数的server提供商也不让你使用自定义系统级别的classloader,因此咱们自动生成的class都将以反射的方式调用。 </p>
<h2>2.在开发阶段自动生成Class</h2>
<p>在开发阶段就自动生成class,而后打包到war包中,这样在server上运行的时候使用咱们生成的class就和通常的方法调用没有任何区别,也就是这一点使得咱们可以规避掉策略1中的弊端。原则上讲着一种方式在开发和打包这两个阶段中多了一个步骤,就是添加自动生成的class,可是因为项目采用MAVEN开发,咱们可以编写一个maven插件,自动的执行自动生成类的打包。因此建议使用这种方式。 </p>
<h1>实现</h1>
<p>目前上述构想已经实现,项目名称为Wheel,而maven插件名称为wheel-maven-plugin。可是wheel所使用的依赖包asmsupport-0.3-SNAPSHOT,classgrep-1.2-SNAPSHOT都尚未release,尚未发布到maven,因此须要手动maven install到本地的maven仓库。各个包编译打包顺序以下: </p>
<ul> <ol>asmsupport执行maven clean install</ol>
<ol>classgrep执行maven clean install</ol>
<ol>wheel执行maven clean install</ol>
<ol>wheel-maven-plugin执行maven clean install</ol> </ul>
<p>这里也有一个简单是实例WheelSampleApp, 里面展现了大部分的功能,如AOP,注入等等。</p>
<p>以上涉及到的项目的源码地址:</p>
<ul> <ol><b>asmsupport:</b>http://code.taobao.org/svn/asmsupport/trunk</ol>
<ol><b>classgrep:</b>http://code.taobao.org/svn/classgrep/trunk</ol>
<ol><b>wheel:</b>http://code.taobao.org/svn/wheel/trunk</ol>
<ol><b>wheel-maven-plugin:</b>http://code.taobao.org/svn/wheel-maven-plugin/trunk</ol>
<ol><b>WheelSampleApp:</b>http://code.taobao.org/svn/WheelSampleApp/trunk</ol> </ul>
<p>Wheel和wheel-maven-plugin正在酝酿发布第一个版本,而calssgrep-1.1和asmsupport-0.2都已经发布,只是wheel所依赖的classgrep-1.2和asmsupport-0.3 这两个新版本还为发布,后续也将补全新功能和bug陆续发布。 </p>