Lisplets:弥合 Lisp 与 Java Servlet 之间的鸿沟
在 2000 年代初期,想要构建 Web 应用的 Lisp 开发者面临的挑战往往是要么重新发明轮子——自己编写 HTTP 服务器和 SSL 处理器,要么在语言的灵活性上妥协。于是 Lisplets 出现了,它是 Rich Hickey 于 2004 年创建的项目,旨在为 Java Servlet 提供 Lisp 友好的接口。
Lisplets 充当桥梁,使开发者能够利用基于 Java 的 Web 环境(如 Tomcat、Jetty 或 Resin)的工业级能力,同时在 Common Lisp 或 Scheme 中编写实际的应用逻辑。通过将 Web 的“管道”工作交给 Java,Lisp 开发者可以专注于语言的表达能力,而不必牺牲可扩展性或安全性。
Lisplets 工作原理
在核心上,Lisplets 由一个实现了 HttpServlet 的单一 Java 类组成。它不在内部处理请求,而是将请求转发并使用 基于 TCP 套接字的 s 表达式 收集响应。
请求流程
- 拦截:Java servlet 容器接收 HTTP 请求。
- 打包:Lisplet servlet 将请求头、参数、Cookie、会话数据、应用状态和用户信息打包成一个 s 表达式。
- 传输:该 s 表达式通过 TCP 套接字发送到监听的 Lisp 进程。
- 处理:Lisp 进程使用标准的
read函数读取 s 表达式,处理逻辑并生成响应。 - 返回:Lisp 进程返回包含状态、头部和会话状态的 s 表达式,随后是原始文档内容。
对 Lisp 开发者的关键优势
通过将 Java servlet 容器用作前端,Lisplets 带来了若干直接的好处:
- 免费基础设施:开发者无需编写任何 Java 代码即可使用专业的 HTTP 服务器实现、SSL 支持以及与行业标准 Web 服务器的集成。
- 企业特性:Lisplet API 完全映射 Servlet API 的强大功能,包括会话管理、认证、访问控制、用户角色以及声明式配置。
- 混合应用:由于它运行在标准的 Java Web 应用中,Lisp 生成的内容可以与 Java Server Pages(JSP)或其他 Java Servlet 共存于同一应用。
- 灵活部署:它兼容任何 servlet 容器,开发者可以根据成本、可嵌入性或平台支持来选择运行环境。
技术深度解析:API
通过 web.xml 配置
Lisplets 通过标准的 web.xml 文件进行配置。lisp-host 和 lisp-port 是定位 Lisp 进程所必需的,而若干可选参数则用于微调:
lisp-tag-prefix:允许开发者在标签前添加字符串(例如:),从而在 Common Lisp 中将其视为关键字。lisp-create-session:布尔值,决定在会话不存在时是否自动创建会话。lisp-roles:以逗号分隔的列表,用于查询用户是否属于特定角色,将 Lisp 逻辑与 Java 的认证系统集成。
请求与响应格式
请求以单个列表的列表形式发送。每个子列表以标签开头(例如 :method、:uri、:headers、:session)。这种结构使 Lisp 进程能够使用标准的列表处理技术轻松解析请求。
响应的结构类似。Lisp 进程必须至少向 Java 端发送一个空列表 ()。响应的 s 表达式可以控制:
- HTTP 状态:设置状态码(例如 200 OK)或触发重定向。
- Cookie:定义名称、值、域和路径。
- 会话/上下文属性:更新 Java 端的动态属性,随后由 servlet 容器持久化。
- 日志记录:将字符串直接发送到
ServletContext日志。
实现示例
Rich Hickey 提供了一个为 Xanalys(LispWorks)编写的示例服务器,以演示集成的简易性。服务器监听端口,从流中读取 s 表达式,并将请求回显为浏览器的响应体:
(defun handle-lisplet-on-stream (stream)
(unwind-protect
(let ((req (read stream)))
(format stream "~S"
`((:status 200)
(:headers (:content-type "text/plain"))
(:log "Hello from Lisp")))
(pprint req stream)
(force-output stream)
(close stream))))
小结
Lisplets 为一个经典问题提供了优雅的解决方案:如何在使用高级、灵活的语言编写逻辑的同时,利用稳定且高性能的基础设施生态系统。虽然该项目始于 2004 年,但其使用简单、语言无关的通信格式(s 表达式)来桥接两种不同运行时环境的理念仍然是一种永恒的架构模式。
Sources
- HNLisplets