`
ZHH2009
  • 浏览: 123691 次
  • 性别: Icon_minigender_1
  • 来自: 天堂
文章分类
社区版块
存档分类
最新评论

Without SSH/JSP/Servlet,不走寻常路,Java可以更酷

阅读更多
标题的构思来源于Rod Johnson的那本"Without EJB"以及CCTV5中一句耳熟能详的广告词,
不过此文并不是用来批判SSH(Struts、Spring、Hibernate)/JSP/Servlet的,
也不是为某品牌做广告,而是用来分享这将近一年来的研究心得。

去年圣诞节时曾在JavaEye发过一两篇文章,不过现在找不到了,
文章内容提到要在3个月左右的时间内设计出一个有别于SSH的新型MVC框架,
设计的起点最初是以JSP/Servlet为基础的,虽然在两个多月后有了个雏形,
但是跟Rails这样的框架相比还是没有明显的优势,
比如在不使用反射的情况下,
很难将不同的uri对应到Servlet类中的public方法。
(Servlet类指的是继承自javax.servlet.http.HttpServlet的类)
每次修改Servlet类的源代码时总得经过烦人的手工编译步骤(有时还不得不重启Tomcat),
还有与数据库打交道的模型层也得人工干预,一堆烦人的映射配置。

那三个月内时常有沮丧感,似乎已走近了死胡同!
后来心一狠,决心甩开JSP/Servlet那一堆条条框框,把设计的起点再往下深一个层次。
因为2007年曾详细研究过Java语言的编译器(javac)实现细节,所以从编译器着手,
但是编译器的强项在于分析Java源代码,无法处理Http请求,
接着在网上把Tomcat6的源代码下下来研究了三个月,
期间顺便研究了Sun公司的超轻量级Http服务器"com.sun.net.httpserver"的源代码,
同时详细学习HTTP/1.0(RFC1945)与HTTP/1.1(RFC2616)协议。

但是Tomcat6过于臃肿了,包含的Java文件超过了1300个,
光是解析server.xml与web.xml的代码看完后就让人有烦躁感。
(如org\apache\tomcat\util\digester与org\apache\catalina\startup包中的很多类)

另外最重要一点,Tomcat6采用的是Eclipse JDT编译器,仅仅是用来编译JSP文件,
编译器在控制层没有发挥一点作用。
而Sun公司的超轻量级Http服务器又过于简单了,连HTTP/1.1的大多数功能都没实现,
除了参考一下它的SSL实现外基本上毫无价值。

本想在现有的JSP/Servlet容器上做一下简单扩展就得了,
哪知也是四处碰壁(还下过Jetty的源代码下来看了一会,结果发现比Tomcat6还糟),
后来决定对Tomcat6与Sun的Http服务器进行大刀阔斧的改造,
完成了一个精简版的改良后的基于NIO的Http服务器(目前的版本只有60个左右的Java源文件),
并且能跟Javac编译器完美结合,能直接运行Java源文件。

在模型层这一块,最初是从书上和网络上对Hibernate进行应用层次的研究,
但是并不想深入源代码,因为代码量也实在是太多了,倒是对Ibatis2.0深入研究了一下,
Ibatis2.0代码量比较少,也简单,看了不到一星期就基本上看完了,不过现在并没留下深刻映象,
因为并没发现什么特别出彩的地方,Ibatis2.0还是离不开xml,而我想要完全抛弃xml。

当然,不管Hibernate也好,Ibatis2.0也好,相比Rails的ActiveRecord还是逊色了点,
不过我的目标并不是要造一个Hibernate、Ibatis2.0或ActiveRecord这样的轮子,
我的要求更高,我在想如何才能写更少的代码,如何才能实现自动化?
可不可以在服务器启动时或运行时动态解析数据库的元数据,
让编译器跟据这些元数据动态生成类呢?
接着我转去研究JDBC-1.2/JDBC-2.1/JDBC-3.0/JDBC-4.0规范,研究数据库驱动的开发手册。
我得从零开始,我目前的实现是这样做的:你可以在你自己的Java源文件中直接引用动态生成的类,
就像这些类是你自己写的一样,ORM已基本上实现自动化了,2.9 节专门讲Douyu的ORM。

最后一点值得一提的是,我在Java语言层次引入了权限管理模型,
不过你别担心,我并没有引入新的Java语言语法,
只是借助Annotation扩充了某些特殊的语义。
目前这个权限管理模型的粒度只是划分为功能、字段权限两个等级,
并没有实现与具体业务相关的数据权限,不过在未来的路线图中有打算引入工作流模型,
到时会努力尝试各种实现数据权限的方案。

与权限相关的细节请看2.8节 Douyu的权限模型



折腾了半年后,发现已不再是个MVC框架了,我想称为平台更合适,
一种运行在JVM之上的新型平台,我给她起了个名字: Douyu
(呵呵,名字的由来暂时保密,也许你能猜出来。。。)



虽然孤军奋战将近一年,自我感觉小有成就,但是还有很多不怎么满意的地方,
各位大牛们也许更牛,看见不爽砸砖头便是。



Ok,上干货。




1. 安装配置


(这里只针对Windows平台,特别是XP操作系统,因为我没其他试验环境)



1.1 安装JDK


Douyu是在JDK1.6下开发的,不支持也不打算支持JDK1.4及更早的版本,JDK1.5我没有测试过,
所以我只能推荐你安装JDK1.6了,安装细节我想你都会,
唯一要注意的一点是:最好是建个JAVA_HOME环境变量,然后把%JAVA_HOME%\bin加入到Path中,
因为在Douyu服务器的启动脚本中并没有进行过多的环境检测,
而是直接使用了%JAVA_HOME%\bin目录下的java命令来启动Java HotSpot VM。


1.2 安装Douyu服务器

Douyu项目主页目前放在:
http://code.google.com/p/douyu/

请先下载二进制版的压缩文件:
http://douyu.googlecode.com/files/Douyu_0_1_0.rar

目前的版本是:0.1.0,版本号很小,但大多数功能都包含了,
我并不推荐你用于工业级别的产品开发,
因为还不稳定,目前只适合分享、交流、尝鲜目的。

下下来后直接解压到一个你选定的目录(假定你解压到了D:\Douyu目录)

D:\Douyu目录里头有下面7个目录(跟Tomcat6差不多):
apps  //应用程序的源代码放在这里,里头有一些java源文件是下面的演示中用到的,当然你可以全都删了。
bin   //服务器的启动脚本和运行时类库都在这里
conf  //服务器的配置文件放在这里
lib   //应用程序使用到的第三方类库(比如数据库驱动)都放在这里,初始情况下是个空目录
logs  //存放服务器运行期间的日志(目前日志只是输出到控制台),初始情况下是个空目录
temp  //服务器运行期间用到的临时文件夹(比如上传文件时可能会用到),初始情况下是个空目录
work  //服务器运行期间的工作目录,初始情况下是个空目录

了解了这些就足够了,目前你不需要做任何配置。







2. 体验Douyu



2.1 如何运行Douyu服务器?


点"开始->运行",输入cmd,打开一个控制台,切换到D:\Douyu\bin目录,
然后输入 douyu  启动Douyu服务器 (要关闭Douyu服务器连按两次Ctrl+C既可)
见下图:



如果你是第一次打开操作系统第一次启动JVM运行Java程序
或是隔了一个小时左右重新启动JVM运行Java程序,这时可能要等待几秒钟(5--10秒),
出现这种情况并不是Douyu服务器的问题,而是JVM本身或操作系统的问题,
通常启动Douyu服务器如果不加载数据库的话,一般在一秒钟内就能启动完成了。

Douyu服务器默认情况下监听的主机名是: localhost,端口: 8000

如果你不喜欢这样的默认配置,
或者最常见的情况是端口8000被占用了
(一般抛出异常: java.net.BindException: Address already in use)
你可以打开conf\server.java这个服务器配置文件,
配置文件本身就是一个java源文件,参数的配置使用Java语言的Annotation语法,
所有与服务器配置有关的都是Annotation或是Enum,全都在com.douyu.config包中定义。
import com.douyu.config.*;

@Server(
	port=8000,
	.................



要修改默认主机名和端口,请修改hostName和port的值,
hostName是一个字符串,可以用IP地址来表示,port是一个整型(int)值。


其他很多参数先不罗列了,使用到时再详细说明。


当你修改了conf\server.java后,你也不需要自己去手工编译它,
启动Douyu服务器时,Douyu会自行决定是否要编译它。
如果conf\server.java存在语法错误,那么编译失败,
Douyu服务器的启动也会失败,同时向你显示编译错误信息。



下文中假定Douyu服务器已启动,监听的主机名是: localhost,端口是: 8000
以下所有例子都经过严格测试了,

我的JRE版本:
D:\Douyu\bin>java -version
java version "1.6.0_16"
Java(TM) SE Runtime Environment (build 1.6.0_16-b01)
Java HotSpot(TM) Client VM (build 14.2-b01, mixed mode, sharing)

测试浏览器用了两个:

傲游浏览器(IE6.0),
谷歌浏览器(Chrome 3.0.195.27)





2.2 Hello World!



2.2.1 程序代码


//对应apps\HelloWorld.java文件

import java.io.PrintWriter;
import com.douyu.main.Controller;

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


2.2.2 手工编译已经Out了,你再也不需要这一步了。


2.2.3 运行HelloWorld

打开你心爱的浏览器,输入 http://localhost:8000/HelloWorld
如果你能看到下图中所示内容,恭喜你,你己经进入了Douyu的精彩世界。



(注:这是你第一次直接运行Java源文件,可能会等几秒钟(2--4秒),因为Douyu得初始化编译器)


2.2.4 程序代码说明

com.douyu.main包中的类大多数是Annotation,还包含一些重要的接口和类,
相当于java.lang,是你用Douyu开发程序时最常用到的,也是通往其他模块的快速入口,
本想让com.douyu.main包中的类像java.lang一样让编译器自动导入的,
但是考虑到很多开发人员更偏爱使用IDE,不同IDE内置的编译器不一样,
从而会引起找不到com.douyu.main包中的类的问题,所以最后决定放弃这样的设计了。

@Controller 这个Annotation是用来告诉Douyu这是一个控制器,
当你在浏览器的地址栏中输入http://localhost:8000/HelloWorld 这样的uri时,
浏览器内部通常会生成一个HTTP GET请求消息,消息内容类似这样:
GET /HelloWorld HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg,......
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon)
Host: localhost:8000
Connection: Keep-Alive

不过这里并不打算介绍HTTP协议,如果你有兴趣,可以把RFC2616下下来研究。

Douyu服务器收到浏览器发来的请求消息后,
特别留意 "GET /HelloWorld HTTP/1.1" 这一行消息,
其中的"/HelloWorld"表示想要获取Douyu服务器上的哪些资源,
资源有静态的(如html、jpg等文件),也有动态的,在Douyu服务器中动态资源只有一种,
凡是带有@Controller这个Annotation的Java源文件都是可以直接通过uri访问的动态资源。

不过Douyu服务器不能根据uri的表面特征一眼就看出它是动态的还是静态资源,
服务器内部有一个专用的资源装载器,装载器的搜索根目录是从apps这个地方开始的,
资源装载器会尝试将apps目录与uri组合成一个java.io.File对象,
如果File对象存在,那么它就是一个静态资源,
然后由Douyu服务器内部的静态资源处理器给浏览器发送包含有文件内容的响应消息;

如果File对象不存在,资源装载器把请求的uri当成一个类名,
然后尝试采用类装载器的方式装载类,如果找不到那么就直接返回未找到(404)消息;
如果找到了,并且uri是第一次请求的,资源装载器会返回java源文件,
然后把java源文件交给Douyu服务器内置的编译器处理,编译器的处理过程很复杂,
这里就不深入说明了,总之它会为你动态生成HelloWorld的实例,
然后调用它的index这个缺省的public方法,
之后调用out.println()方法把"Hello World!"发送给浏览器。
  • 大小: 27.3 KB
  • 大小: 8.7 KB
  • 大小: 14.8 KB
  • 大小: 13.2 KB
  • 大小: 13.4 KB
  • 大小: 11.1 KB
  • 大小: 20.4 KB
  • 大小: 27.3 KB
  • 大小: 63.7 KB
  • 大小: 75.4 KB
  • 大小: 14.7 KB
  • 大小: 22.6 KB
  • 大小: 22.4 KB
  • 大小: 22.8 KB
  • 大小: 24.4 KB
  • 大小: 23.9 KB
  • 大小: 28.5 KB
  • 大小: 36.9 KB
  • 大小: 24.1 KB
  • 大小: 52.6 KB
  • 大小: 77.3 KB
  • 大小: 101.3 KB
  • 大小: 54.2 KB
  • 大小: 122 KB
分享到:
评论
402 楼 doinsist 2010-11-10  
楼主,真厉害,我为了回复一下回答了好多问题。。。
401 楼 大海lb 2010-11-05  
楼主太强大了,我敬佩你
400 楼 大海lb 2010-11-05  
牛人啊,羡慕,高技术的就是不一样,好喜欢你哦。。。
399 楼 borland 2010-11-01  
楼主可否给个源代码学习下,或者关键代码也行
398 楼 yjshengshe 2010-10-31  
楼主,强人,期待楼主最新的研究成果。
397 楼 allcan 2010-10-29  
中国的大牛啊~
偶像,我还有很远的路要走啊,敬佩~搂住再接再厉~
396 楼 mdsp25xhm 2010-10-29  
哗~~骄傲,牛人也!
395 楼 sylarHong 2010-10-26  
强,有很多值得学习的地方。
394 楼 DOCDOC 2010-10-26  
rebornsteven 写道
想不到俺们广西还有这么牛的大神,不知道douyu现在是否有源码  可供我们这些小辈学习学习

大多数哭着喊着求源代码的主儿,是没这个水平看源代码的。
393 楼 掏掏潇雨 2010-10-26  
。。。LZ爆强,tomcat的代码我就没看懂
392 楼 ideniece 2010-10-25  
原来牛人是这样炼成的
391 楼 1sun1 2010-08-25  
LZ让我明白了,当初我为什么想成为一个JAVA程序员
你是我的偶像,也是我继续努力学习的动力
390 楼 kingsli 2010-08-17  
楼主疯了,过不到好久可能要出更疯狂的人物了
389 楼 herozk 2010-08-15  
asdasd
388 楼 rebornsteven 2010-08-13  
想不到俺们广西还有这么牛的大神,不知道douyu现在是否有源码  可供我们这些小辈学习学习
387 楼 yonlist 2010-08-13  
非常佩服LZ,我一直都在思考比Servlet更轻量级的方式
386 楼 ZHH2009 2010-08-13  

最近工作上的事情太多,好久没写点东西了,
不过我是建议大家不要顶这个帖了吧,特别是一些显得有些夸张的赞美,
听得多了,我都差不多快吐了 ,估计其他人看了也烦,如果实在想说,就发到我博客上吧,
那里发再多的水帖也不会污染大家的视线。 


385 楼 mmBlue 2010-08-12  
原来听项目经理提过douyu。。。今天膜拜一下,楼主真乃神人也。。。
384 楼 jh108020 2010-08-12  
lz真是神人,佩服
383 楼 sbfeeq 2010-08-12  
回复个话,要回答N个问题,烦啊

相关推荐

    《Java Servlet编程(第二版)》英文版 chm (含源码)

    The Java 2, Enterprise Edition (J2EE), specification has included servlets as a core component, and application server vendors wouldn't be caught dead without a scalable servlet implementation....

    test-servlet3-without-webxml.rar

    综上所述,`test-servlet3-without-webxml.rar`文件提供了关于Servlet 3.0无web.xml配置的实践案例,通过学习和分析这个项目,开发者可以深入理解Servlet 3.0的新特性和优势,提升Java Web开发技能。

    SSH移植到android系统步骤.doc

    SSH移植到Android系统步骤 SSH(Secure Shell)是一种安全的远程登录协议,常用于Linux系统中。但是,Android系统并不具备SSH功能,这篇文章将讲述如何将OpenSSH移植到Android系统中。 Step 1: 获取OpenSSH源码 ...

    Hadoop ubuntu 9.10 下的 SSH 免登陆

    4. **配置SSH**:编辑`/etc/ssh/sshd_config`文件,确保`PermitRootLogin`设置为`without-password`或`no`,以禁止root用户通过密码登录。同时,确认`PubkeyAuthentication`设置为`yes`,启用公钥认证。 5. **重启...

    Servlet查询数据库案例--Query(java源码)

    * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied. * You may study, use, and modify it for any non-commercial purpose. * You may distribute it non-commercially as long as you...

    批量配置服务器ssh免密rsa登录

    免密登录是SSH的一种功能,通过公钥认证方式,用户可以在不输入密码的情况下登录远程服务器,极大地方便了多服务器管理和自动化运维。 标题“批量配置服务器ssh免密rsa登录”所涉及的知识点主要包括: 1. **RSA...

    openssh-server -Ubuntu18.04远程服务离线安装包

    依次运行下面命令进行安装: sudo dpkg -i openssh-client_1%3a7.6p1-4ubuntu0.6_amd64.deb sudo dpkg -i ncurses-term_6.1-1ubuntu1.18.04_all.deb ... 删除permitRootLogin后面的without-password后改为yes

    SSH无密码登录配置(主要针对Hadoop配置)

    SSH(Secure Shell)是一种网络协议,用于在不安全的网络上提供安全的远程登录和其他服务。在Hadoop这样的分布式计算环境中,SSH无密码登录配置至关重要,因为它简化了节点间的通信,提高了运维效率。以下是关于SSH...

    Redis-desktop redis管理工具 支持SSH 无bug版

    在这个特定版本中,开发者声称已经解决了所有已知的bug,这意味着用户可以享受到更稳定、更流畅的使用体验。 描述中的"支持SSH,SSL,Advanced settings"进一步揭示了这款工具的功能特性。除了SSH,它还支持SSL...

    ssh服务安装软件及其操作步骤.zip

    在Linux系统中,SSH(Secure Shell)是一种网络协议,用于安全地远程登录到服务器,执行命令,传输文件等。SFTP(Secure File Transfer Protocol)是SSH的一部分,提供了一个安全的文件传输机制。在这个名为"ssh服务...

    三大技术javaBean+servlet+jsp常见问题和解决方案

    在 JSP 页面中使用 `<c:when>` 标签时,如果没有将其放在 `<c:choose>` 标签的直接子元素中,则会抛出 `javax.servlet.ServletException: Illegal use of <when>-style tag without <choose> as its direct parent` ...

    servlet2.4doc

    Overrides the standard java.lang.Object.clone method to return a copy of this cookie. containsHeader(String) - Method in class javax.servlet.http.HttpServletResponseWrapper The default behavior of ...

    Ubuntu 16.04远程登录服务器ssh的安装和配置.pdf

    在 Ubuntu 16.04 中,默认情况下已经安装了 openssh-client,为了避免与 openssh-server 不匹配,需要卸载原有的 ssh-client 和 ssh-server,然后重新安装 openssh-server 和 openssh-client。 卸载原有的 ssh-...

    OpenSSH 9.3 CentOS7 RPM安装包

    基于centos7编译的openssh9.3的安装包,使用x11-ssh-askpass让openssh不在依赖openssl1.1.1。 更新前:注意备份好/etc/ssh和/etc/pam.d/ ,一般建议开启telnet增加一条备用登陆通道 更新操作:rpm -Uvh openssh-*....

    eclipse 反编译插件 java工具JadClipse

    eclipse 反编译插件 java工具JadClipse 将JadClipse插件(net.sf.jadclipse_3.3.0.jar)拷贝到{EclipseHome}/plugins文件夹下(如C:\Program F\eclipse-jee-kepler-R-win32-x86_64\eclipse\plugins)。JAD 解压到...

    FreeBSD 8.0 配置密钥登录

    - **PermitRootLogin**: 设置为`without-password`,表示root用户可以使用密钥认证登录,但不能使用密码登录。 下面是修改后的部分配置示例: ``` Protocol 2 RSAAuthentication yes PubkeyAuthentication ...

    Anolis8.x rpm升级openssh9.6

    在Linux系统管理中,安全是至关重要的,OpenSSH作为一个开源的Secure Shell (SSH)协议实现,为远程登录、文件传输等提供了加密保障。本话题主要关注如何在Anolis8.x操作系统上,通过RPM(Red Hat Package Manager)...

    java嵌入式tomcat[借鉴].pdf

    这些 Jar 包包括 Tomcat 的核心包、servlet-api.jar 和 javax.servlet.jsp-api.jar 等。这些 Jar 包可以从 Apache Tomcat 的官方网站下载。 接下来,在 src 目录下创建一个 conf 目录,用于存放 Tomcat 的配置文件...

    ubuntu16.04服务器配置ssh免密码登录

    SSH (Secure Shell) 是一种网络协议,用于在不安全的网络上安全地远程登录到Linux或Unix服务器。在Ubuntu 16.04系统中,配置SSH免密码登录可以简化管理任务,避免每次连接时输入密码的繁琐过程。以下是详细步骤和...

    ssh移植到arm版文件.rar

    SSH(Secure Shell)是一种网络协议,用于在不安全的网络上提供安全的远程登录和其他服务。在嵌入式系统,如ARM架构的设备上,SSH的移植是确保设备管理安全性和远程访问的重要步骤。本文将深入探讨如何将SSH移植到...

Global site tag (gtag.js) - Google Analytics