当前位置: 代码迷 >> Web前端 >> Douyu 0.6.1公布了,这是一个超乎您想象的Web框架
  详细解决方案

Douyu 0.6.1公布了,这是一个超乎您想象的Web框架

热度:318   发布时间:2012-09-06 10:37:01.0
Douyu 0.6.1发布了,这是一个超乎您想象的Web框架

?

自从2009年11月份发布第一个原型版本后,(见这里)

时间一恍就过去了1年半,

这段时间主要忙于工作了(从事分布式数据访问、存储以及Web容器方面的工作),

所以douyu一直处于停滞状态,直到今年3月份开始才能将1/3的时间投入到上面。


最初的版本抛弃了Servlet/JSP规范,并且自已实现容器,这思路理论上是没有大的错的,

但是太新潮了,原有的技术积累不能充分使用,所以但凡追求稳定第一的产品都不敢贸然尝试。


因此,douyu的设计思路也跟着变了,努力的方向是:

尽量兼容现有技术、寻求一种更简单更有效的办法改进现有技术。

?

douyu 0.6.1往这个方向迈出了第一步,?

第一步主要关注Web层的东西,不涉及持久层,douyu 0.6.1包含了如下亮点:

?

1. 兼容Servlet/JSP,使用douyu提供的api写出的程序能部署到Servlet容器上(例如Tomcat、Jetty)


2. 基于Javac编译器技术,实现零配置,无需打包、部署,无需重启Servlet容器,直接运行Java源文件。


3. 支持Velocity、FreeMaker,集成其他模板引擎也是非常简单,多种模板引擎可以在同一个应用中同时使用。


4. 学习成本非常低,目前只需要学习5个接口(不超过15个方法)。


5. douyu 0.6.1源代码不超过1500行,所以非常适合初学者入门,如果想达到另一个境界,可以继续看Javac编译器的代码。

?

?

?

?

Douyu项目主页目前放在:?

http://code.google.com/p/douyu/?

?

?

以下是例子:

?

(可以从发布包的douyu-examples\WEB-INF\src中找到这些例子)

?

?

Hello World

?

?

@Controller
public class HelloWorld {
	public void index(PrintWriter out) {
		out.println("Hello Douyu World!");
	}
}
?

?

?

自动提取HTML表单参数:?

?

?

<FORM METHOD=POST ACTION="FormExample.save">  
    姓名:<INPUT TYPE="text" NAME="name" VALUE="haha">
    年龄:<INPUT TYPE="text" NAME="age" VALUE="100">  
    <INPUT TYPE="submit">  
</FORM>
?

?

?

@Controller
public class FormExample {
	public void save(String name, int age) {
		...
	}
}
?

?

文件上传

?

?

    <FORM ENCTYPE="multipart/form-data" METHOD="POST" ACTION="FileUpload.upload">
    文件1:<INPUT NAME="file1" TYPE="file" size="50"><br>
	文件2:<INPUT NAME="file2" TYPE="file" size="50"><br>

	说明 :<TEXTAREA NAME="description" ROWS="5" COLS="50"></TEXTAREA><br>

    <INPUT TYPE="submit" VALUE="上传">
    </FORM>
?

?

?

@Controller
public class FileUpload {
	public void upload(Part[] parts, Part part, String description) {
		part.write(...);
	}
}
?

?

嵌套Model自动注入:

?

?

@Model
public class Consumer {
	private String name;
	private Address address;

	public void set(String name, Address address) {
		this.name = name;
		this.address = address;
	}
}

@Model
public class Address {
	private String country;
	private String city;

	public void set(String country, String city) {
		this.country = country;
		this.city = city;
	}
}
?

?

?

@Controller
public class ModelInjectExample {
	//通过这个url访问
	//ModelInjectExample?consumer.name=zhh&consumer.address.country=china&consumer.address.city=hangzhou

	//输出:
	//consumer=Consumer[name=zhh, address=Address[country=china, city=hangzhou]]
	public void index(Consumer consumer, PrintWriter out) {
		out.println("consumer=" + consumer);
	}
}
?

?

?

最炫的功能:

?

可以在JSP、Velocity、FreeMaker中直接访问控制器Action中的本地变量:

?

?

@Controller
public class ViewManagerExample {
	public void soCool(ViewManager v, String name, int age) {
		Date date = new Date();
		v.out("/jsp/ViewTest.jsp");
		v.out("/ViewTest.vm");
		v.out("/ViewTest.ftl");
	}
}
?

?

ViewTest.vm

?

?

<HTML>
<HEAD>
<TITLE>ViewManager Test</TITLE>
</HEAD>

<BODY BGCOLOR="white">
name = ${name} <br>
age = ${age} <br>
date = ${date} <br>
</BODY>

</HTML>
?

?

?

异步Action

?

?

@Controller
public class AsyncTest {
	public void asyncAction(HttpServletRequest request) {

		if (request.getAttribute("async-result") != null) {
			doSomething();

			request.getAsyncContext().complete();
		} else {
			AsyncContext actx = request.startAsync();
			actx.setTimeout(10000);

			invokeLongTimeService(actx);

			....
		}
	}
}
?

?

?

最后,源代码在这,赶紧凑凑热闹吧:

svn checkout http://douyu.googlecode.com/svn/trunk/ douyu-read-only

?

google code的svn不太稳定,时好时坏:

源代码压缩包: 点我

?

?

?

38 楼 zhangyou1010 2011-06-01  
去年在江南白衣发布springside的某个版本的时候,提到过斗鱼,现在终于有缘相见,down下来慢慢学习。
39 楼 kjj 2011-06-01  
神器再出江湖,希望作者一鼓作气,捣鼓出来个东西来,个人严重支持一下,刚看到就被评为良好了,我没机会了.......555555555555555555555555
40 楼 denger 2011-06-01  
很不错... !!
41 楼 surpass 2011-06-01  
ZHH2009 写道
yangfuchao418 写道
从一开始就关注斗鱼,和作者,原来觉得还是不错的。现在仅觉得是一个技术民工的狂热产物。当然也许人各有志,不便于评论。哥还不如把这么大的精神那去创业,不过即使创业楼主也难以理性分析。点子也难以创新吧


真的是人各有志,比如我就喜欢走路上班不喜欢开宝马上班,

我就是一码农,我没觉得什么不好,我过得很充实,我喜欢这样的生活。


强迫别人走自己的路是非常可耻的。

现在真的想lz这样的研究技术的人太少了。真的佩服
42 楼 surpass 2011-06-01  
nirvana1988 写道
楼主,按照这个路径http://douyu.googlecode.com/svn/trunk/ douyu-read-only在SVN上检出你这项目的源码,提示没有此文件夹~~


多了个空格。

trunk/后面
43 楼 sd_zyl 2011-06-02  
楼主辛苦~~请教一下:
项目打包后生成后的jar包似乎和以前版本不兼容,那个启动engine包没有了~直接替换去年douyu.jar,服务器启动不了了~~
烦请楼主给个范例
44 楼 ZHH2009 2011-06-02  
sd_zyl 写道
楼主辛苦~~请教一下:
项目打包后生成后的jar包似乎和以前版本不兼容,那个启动engine包没有了~直接替换去年douyu.jar,服务器启动不了了~~
烦请楼主给个范例



这个0.6.1版和前面那个版本是不一样的,0.6.1版的douyu不是一个独立的容器了,
要放到Tomcat或Jetty上面跑,你直接把douyu-examples那个目录放到Tomcat或Jetty的webapps目录下,
启动Tomcat或Jetty就可以通过 http://127.0.0.1:8080/douyu-examples/ 这样的url来访问了。

可以看看douyu-0.6.1.zip中的那个readme.txt文件。

0.6.1版的douyu是很不成熟的,建议在闲暇之余稍微了解一下她的不同思路就可以了,

目前不建议用于任何规模的产品开发。
45 楼 Angly1018 2011-06-02  
关注斗鱼,down下来看看
46 楼 edokeh 2011-06-02  
我觉得,唯有偏执狂才TM能生存

LZ其实不必考虑兼容servlet,本来你这套东西跟servlet就不是一路,你也不会指望以前用servlet的人会迁移到douyu上,所以,果断抛弃servlet,douyu会有更广阔的发展空间
47 楼 rhuichao 2011-06-02  
这个得赞一个
48 楼 zdmcjm 2011-06-03  
模版直接引用本地变量,这个比较赞。
我自己也在playframework框架中实现了。
不过我是做了一些约定,在模版中引用的方法局部变量一定要以“_”开头。
如:public static void show(Long id){
User _user = User.findById(id);
}
这个_user会自动put到模版中。

我个人是比较喜欢prototype模式的controller,所以play也不算我满意的框架,如果douyou只支持singleton,我的兴趣就不太大了,哈。
另外套个近乎,都是讲桂柳话的。
49 楼 iaimstar 2011-06-03  
额.....为啥不是精华?
50 楼 ZHH2009 2011-06-03  
edokeh 写道


LZ其实不必考虑兼容servlet,本来你这套东西跟servlet就不是一路,你也不会指望以前用servlet的人会迁移到douyu上,所以,果断抛弃servlet,douyu会有更广阔的发展空间



douyu兼容servlet是非常容易的,douyu的基本设计原则是鼓励开发者面向接口编程,
开发者写程序时只要知道底层框架提供了那些接口,
然后在运行时底层框架会把这些接口的具体实现注进来,
javax.servlet和javax.servlet.http这两个包中基本上都是一些接口,
douyu.mvc也是主要由接口组成。

反观playframework框架,看看它的api文档吧,一大堆的类,非常不直观,
api文档完全没有区分框架用户和框架开发人员,有些api用户根本不需要了解。


zdmcjm 写道

我个人是比较喜欢prototype模式的controller,所以play也不算我满意的框架,如果douyou只支持singleton,我的兴趣就不太大了,哈。
另外套个近乎,都是讲桂柳话的。


这个很容易实现的,在@Controller中加个属性就可以了(比如@Controller(singleton=true)).

其实,完全可以不用任何@Controller这样的注解的,
可以默认建个目录比如controllers,所有在这个目录中的类都默认是Controller,
后来我发现这种方式不灵活,如果你要为某个Controller添加一些额外的功能:
比如Controller只能处理POST请求、比如要进行权限认证、比如有最大线程限制,

这时又不得不搞个配置文件在里面配这些参数,这时又回到了在web.xml中配servlet的方式,
所以用注解是最好的办法,注解就是用来设置参数并调整Controller的行为的,
比如@Controller(httpMethods=HttpMethod.POST)就可以做到让这个Controller的所有Action都只处理POST请求,

再比如@Controller(maxThreads=50),如果这个Controller的某个Action由于执行了某个操作被堵住了,
这个maxThreads参数就能保护系统资源不会被这个Controller耗尽,最多只允许50个线程在并发执行这个Controller,
甚至可以做到按当前系统的服务质量来动态调整所有Controller的行为。
51 楼 yin_bp 2011-06-03  
AlwenS 写道
楼主 写道
最炫的功能:
可以在JSP、Velocity、FreeMaker中直接访问控制器Action中的本地变量:


为啥没人吐槽这个功能呢? 的确很炫,居然可以访问局部变量,应该是对javac动了手脚了,使bytecode记录了更多信息了吧?对性能有影响不?


想问下,这个局部变量的使用范围,会不会和其他的全局变量像冲突,另外是不是会把嵌套方法中的局部变量也当做本地变量来使,如果是这样的话,是否会有命名冲突的问题哦,这个变量值以谁为准啊。
52 楼 ZHH2009 2011-06-03  
yin_bp 写道
楼主 写道
最炫的功能:
可以在JSP、Velocity、FreeMaker中直接访问控制器Action中的本地变量:


想问下,这个局部变量的使用范围,会不会和其他的全局变量像冲突,另外是不是会把嵌套方法中的局部变量也当做本地变量来使,如果是这样的话,那就悲剧了。


根据变量可见性规则,如果局部变量跟全局变量(比如实例变量)同名时,局部变量是会把实例变量覆盖掉的,
我觉得也是可以在模板中加this前缀来解决这些问题,就如同你在java代码中为了访问实例变量加了this一样,

嵌套方法中的变量不会加进来的,

如果在out方法后新定义了一些局部变量,也不能在out(viewFileName)对应的模板中访问的。


最简单的理解是:
这个功能,你可以想像成把模板文件中的每一行内容都内联到java代码中了,像这样:
out.println("....." + localVarName + "....");
out.println("....." + this.instanceVarName + "....");
53 楼 yin_bp 2011-06-03  
引用
异步Action
@Controller 
public class AsyncTest {  
    public void asyncAction(HttpServletRequest request) {


哦,再请教两个问题:
1.douyu的控制器是不是只能有一个控制方法,如果允许多个方法的话,那么异步调用为每个方法请求公用一个线程池还是单个线程池。
2.douyu的异步action是每个action分派一个线程池,还是全部采用一个线程池
54 楼 ZHH2009 2011-06-04  
<div class="quote_title">yin_bp 写道</div>
<div class="quote_div">
<br>douyu的控制器是不是只能有一个控制方法<br>
</div>
<p><br>一个控制器可以有多个action,所有的public方法(排除static方法)都是action,都可以通过"/包名/简单类名.方法名"这样的url访问。<br></p>
<div class="quote_title">yin_bp 写道</div>
<div class="quote_div">
<br>如果允许多个方法的话,那么异步调用为每个方法请求公用一个线程池还是单个线程池。<br>2.douyu的异步action是每个action分派一个线程池,还是全部采用一个线程池<br>
</div>
<p><br>首先要说明一点:<br><br><span style="color: #008000;">异步action是基于servlet3.0规范中的异步servlet实现的,</span><br><br>出现异步servlet的最根本原因是:<br><br>当请求处理逻辑走到业务代码时(通常是从进入javax.servlet.Servlet.service方法开始),<br>如果业务代码在执行一个很耗时的计算或者调用的服务很久都没结果导致一直在死等,<br>那么当前线程(正常来说是容器的内部线程)就不能往下走了,就被卡住了,<br>另外一个同样的请求进来时,容器又要用另外一个线程执行Servlet.service方法,在执行到这个业务代码时也被卡住了,<br>从而导致容器内部线程池一下就耗尽了,无法执行其他的Servlet。<br><br>异步servlet,就是为了解决这个问题,如果开发人员提前意识到业务代码可能把容器的内部线程卡住,<br>那么此时他就应该用异步servlet,这样这个Servlet.service方法就有可能在一次请求中被重复执行多次,<br>相当于容器有一个很大的循环,在不停的执行Servlet.service方法,<br>直到那个很耗时的计算完成或服务超时就可以结束请求。<br><br>所以不管是异步servlet还是异步action,这里说的线程池是容器内部的线程池。<br><br>当然,在使用异步servlet时,<br>一般来说应用开发人员都会为这些耗时的计算或者可能会出现问题的服务建立一个公用的业务线程池,<br>但是这个业务线程池并不是由容器来管理的,即使这个公用的业务线程池被耗尽了,<br>容器自己的线程池还是可以处理其他类型的请求。</p>
<p>?</p>
55 楼 yin_bp 2011-06-04  
呵呵,解释的非常清楚,赞
不过,异步处理最大的挑战在于资源冲突、死锁以及超时处理等问题,综合考虑起来还是挺复杂的。
56 楼 sebatinsky 2011-06-08  
呵呵,保留意见,不过还是支持开源洞洞
57 楼 windlike 2011-06-12  
好,很好,very good