35、最简单的mvc框架tiny,V2版原理图、设计

时光总嘲笑我的痴心妄想 提交于 2020-04-07 05:45:26

在前面的v1版,由于我们临时起意,存在不少问题,我重新设计框架v2版chen(重名问题改名为chen)。

原理图如下:

先说下chen框架的功能:

  1. restful地址支持(chen中叫路由)。
  2. mvc功能,使用简单。
  3. 多视图支持,支持自定义扩展。
  4. action支持同步和异步请求。
  5. 充血模型。
  6. aop功能。
Ioc为容器,管理这所有action和mo del,框架使用者同样可以使用ioc。
  1. 多数据库支持,通过工厂支持多数据库实现,支持自定义扩展。
  2. orm功能,使用简单,无需定义xml、注解等。
  3. 简单,核心类只有10几个。

设计思路如下:

  1. 以前置控制器接受用户特定请求,如果为action请求,则将请求地址转化为路由(/类/方法/)。
  2. 根据用户的请求类型(同步或异步),创建执行环境,交给不同的handler来处理。
  3. handler以初始化、执行、渲染视图、销毁资源4个步骤一次执行。
  4. handler执行:从执行环境(执行环境从ioc容器中取出action和aop)中取出action、aop等信息,调用aop和action。
  5. handler渲染视图:根据action返回的类型,渲染视图和保存数据。
  6. handler销毁资源:销毁执行环境。
  7. action中使用的model模型,是从ioc容器中取出。
  8. model模型通过工具类获得合适数据库操作。工具类通过工厂类获得。
  9. 工厂类会初始化数据库、数据库连接池等。

视图实现:


  1. 定义抽象类Renderer,定义render方法渲染视图,然后实现不同的视图渲染,如JspRendererFileRenderer等jsp和文件视图。
  2. 实现同步和异步视图。如JspRenderer、JspAsyncRenderer(异步)。


控制器实现:


  1. 已servlet 3.0注解方式实现Filter,接受特定的同步/异步请求的前置控制器。
  2. 约定以Action结尾的类,为action类。
  3. 从1和2我们能实现彻底0配置。


模型实现:


  1. 约定以Model结尾的类,为model模型类。
  2. 一个model类的名字(去掉model,小写后)对应一张数据表。实现orm功能。

Aop实现:


  1. 定义aop接口,定义action执行前后拦截方法。
  2. 绑定自定义的aop类和路由关系。如:/TinyTest/hello/=web.TestAop

Ioc实现:


  1. 定义接口IChen,定义方法,如添加类、取出类、接口实现等。
  2. 在前置控制器启动时,初始化ioc。(自动将action和model放入ioc容器)

仓储实现:


  1. 定义接口IRepository定义同数据库交互方法。
  2. 实现oracle、mysql等实现。
  3. 定义工厂类,用户使用dao工具类时,自动适应数据库类型。
  4. 实现数据库连接池,有工厂类初始化。


整体处理流程如下:

用户在页面发起了一个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;
    }
}












易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!