在前面的v1版,由于我们临时起意,存在不少问题,我重新设计框架v2版chen(重名问题改名为chen)。
原理图如下:
先说下chen框架的功能:
- restful地址支持(chen中叫路由)。
- mvc功能,使用简单。
- 多视图支持,支持自定义扩展。
- action支持同步和异步请求。
- 充血模型。
- aop功能。
- 多数据库支持,通过工厂支持多数据库实现,支持自定义扩展。
- orm功能,使用简单,无需定义xml、注解等。
- 简单,核心类只有10几个。
设计思路如下:
- 以前置控制器接受用户特定请求,如果为action请求,则将请求地址转化为路由(/类/方法/)。
- 根据用户的请求类型(同步或异步),创建执行环境,交给不同的handler来处理。
- handler以初始化、执行、渲染视图、销毁资源4个步骤一次执行。
- handler执行:从执行环境(执行环境从ioc容器中取出action和aop)中取出action、aop等信息,调用aop和action。
- handler渲染视图:根据action返回的类型,渲染视图和保存数据。
- handler销毁资源:销毁执行环境。
- action中使用的model模型,是从ioc容器中取出。
- model模型通过工具类获得合适数据库操作。工具类通过工厂类获得。
- 工厂类会初始化数据库、数据库连接池等。
视图实现:
- 定义抽象类Renderer,定义render方法渲染视图,然后实现不同的视图渲染,如JspRenderer、FileRenderer等jsp和文件视图。
- 实现同步和异步视图。如JspRenderer、JspAsyncRenderer(异步)。
控制器实现:
- 已servlet 3.0注解方式实现Filter,接受特定的同步/异步请求的前置控制器。
- 约定以Action结尾的类,为action类。
- 从1和2我们能实现彻底0配置。
模型实现:
- 约定以Model结尾的类,为model模型类。
- 一个model类的名字(去掉model,小写后)对应一张数据表。实现orm功能。
Aop实现:
- 定义aop接口,定义action执行前后拦截方法。
- 绑定自定义的aop类和路由关系。如:/TinyTest/hello/=web.TestAop
Ioc实现:
- 定义接口IChen,定义方法,如添加类、取出类、接口实现等。
- 在前置控制器启动时,初始化ioc。(自动将action和model放入ioc容器)
仓储实现:
- 定义接口IRepository定义同数据库交互方法。
- 实现oracle、mysql等实现。
- 定义工厂类,用户使用dao工具类时,自动适应数据库类型。
- 实现数据库连接池,有工厂类初始化。
整体处理流程如下:
用户在页面发起了一个action的请求,前置控制器截获了这个请求,验证之后,将请求地址转化为路由,根据请求类型同步或异步,生成执行环境(包括:Request、路由、action实例、方法、参数等),将执行环境放入handler中(同步或异步请求,有不同的handler,也可以自定义扩展),handler依次执行:初始化、执行、渲染视图、销毁资源4个步骤处理请求,在执行时先执行aop before,然后执行action,action中调用的model,从ioc容器获得,model使用dao工具类,操作数据库。再执行aop after。渲染视图是根据action返回结果,渲染特定视图或保存数据。最后销毁资源。
代码
前置控制器FrontControl.java
package chen;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.servlet.AsyncContext;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import chen.aop.Binder;
import chen.ioc.Chen;
import chen.util.ContextUtil;
@WebFilter(urlPatterns = { "/ty/*" }, asyncSupported = true)
public class FrontControl implements Filter{
private AtomicBoolean initialized = new AtomicBoolean();
private ServletContext servletContext;
@Override
public void init(final FilterConfig config) throws ServletException{
try {
if (initialized.compareAndSet(false, true)) {
long time1 = System.currentTimeMillis();
this.servletContext = config.getServletContext();
Scaner.run();
Binder.load();
System.out.println(">>> chen 已经启动,用时"+(System.currentTimeMillis()-time1)/1000+"秒");
}
}
catch (Exception e) {
throw new ChenException(" >>> chen 启动失败",e);
}
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws ServletException, IOException{
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
String[] routes = valid(req);
if(routes == null){
chain.doFilter(request, response);
return;
}
try {
long time1 = System.currentTimeMillis();
Context context = null;
IHandler handler = null;
if(routes[0].endsWith("Async")){
AsyncContext async = req.startAsync();
async.setTimeout(30*1000);
context = new Context(routes,Scaner.getCls(),Binder.getAop(routes),req,res,servletContext,async);
async.start(new AsynHandler(context));
}else{
context = new Context(routes,Scaner.getCls(),Binder.getAop(routes),req,res,servletContext);
handler = new ChenHandler(context);
handler.init();
}
System.out.println(">>> chen 处理路由/"+routes[0]+"/"+routes[1]+"/完成,用时"+(System.currentTimeMillis()-time1)/1000+"秒");
}
catch (Exception e) {
throw new ChenException(" >>> chen 处理路由/"+routes[0]+"/"+routes[1]+"/失败",e);
}
}
private String[] valid(HttpServletRequest req){
String uri = req.getRequestURI();
String path = req.getContextPath();
if (path != null){
uri = uri.substring(path.length());
}else{
return null;
}
String[] routes = uri.substring(uri.indexOf("/ty/")+4).split("/");
if(routes == null || routes.length<2){
return null;
}
return routes;
}
@Override
public void destroy() {
}
}
执行环境Context.java
package chen;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;
import javax.servlet.AsyncContext;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import chen.aop.Aop;
import chen.ioc.Chen;
import chen.util.ChenMap;
public class Context {
public final Map<String,String> cls;
public final Object[] aops;
public final String[] routes;
public final HttpServletRequest reqs;
public final HttpServletResponse resp;
public final ServletContext servletContext;
public final AsyncContext async;
public final Object instance;
public final Method method;
public final Map<String,Object> args;
public Context(String[] routes,Map<String,String> cls,String[] aops,HttpServletRequest reqs,HttpServletResponse resp,ServletContext servletContext) throws ClassNotFoundException, SecurityException, NoSuchMethodException{
this.cls = cls;
this.aops = this.converter(aops);
this.routes = routes;
this.reqs = reqs;
this.resp = resp;
this.servletContext = servletContext;
this.instance = Chen.container.get(Class.forName(this.cls.get(this.routes[0]+"Action")));
this.method = this.instance.getClass().getMethod(routes[1],Map.class);
this.args = this.converter(this.reqs.getParameterMap());
this.async = null;
}
public Context(String[] routes,Map<String,String> cls,String[] aops,HttpServletRequest reqs,HttpServletResponse resp,ServletContext servletContext,AsyncContext async) throws ClassNotFoundException, SecurityException, NoSuchMethodException{
this.cls = cls;
this.aops = this.converter(aops);
this.routes = routes;
this.reqs = reqs;
this.resp = resp;
this.servletContext = servletContext;
this.instance = Chen.container.get(Class.forName(this.cls.get(this.routes[0]+"Action")));
this.method = this.instance.getClass().getMethod(routes[1],Map.class);
this.args = this.converter(this.reqs.getParameterMap());
this.async = async;
}
private Object[] converter(String[] aops) throws ClassNotFoundException{
Object[] aopIns = null;
if(aops !=null && aops.length>0){
aopIns = new Object[aops.length];
for(int a=0;a<aops.length;a++){
aopIns[a] = Chen.container.get(Class.forName(aops[a]));
}
}
return aopIns;
}
private Map<String,Object> converter(Map<String,String[]> args){
if(args == null){
return null;
}
Map<String, Object> params = new ChenMap();
for(String key : args.keySet()){
params.put(key, Arrays.toString(args.get(key)).replaceAll("[\\[\\]\\s,]", ""));
}
return params;
}
}
来源:oschina
链接:https://my.oschina.net/u/933274/blog/227074