Clojure 提供了良好的 Java 互操作性。但是,我真的很想拥有这个:
(servlet IndexServlet
(service[parmas] ....)
(do-post[params] ....)
(do-get [params] ....))
(servlet-filter SecurityFilter
(do-filter [params] ....))
我想这就是所谓的 DSL,在 Lisp 世界中它是通过宏完成的。
我不确定如何/从哪里开始。 refiy 和 extends 形式在这里肯定有重要作用,但我不知道这将如何适应宏。
如何开始做这个 DSL?
非常感谢一个片段、提示和技巧。
最佳答案
您可能想查看 Ring 的 Jetty 适配器,以获取 Clojure 中 servlet 实现的示例。源码可用here (链接到 1.1 版本的源代码)。特别是,该命名空间中定义的第一个函数 proxy-handler
返回一个基于 Jetty 提供的抽象类的处理程序。
如果您选择实现类似的方法(将您的 servlet 基于提供一些现成方法实现的 Java 类),您将需要使用 proxy
;如果您只需要实现接口(interface)(没有子类化),那么您可能需要 reify
。宏是否有用取决于实现的哪些部分将被修复; Ring 的 Jetty 适配器不会从宏的使用中获益,但您可以(例如,如果您希望将要扩展的类/接口(interface)实现到一个参数中,正如问题似乎表明的那样)。
在任何情况下,无论您选择实现哪个功能,都需要成为接口(interface)或协议(protocol)的一部分。因此,实现 javax.servlet.Servlet
加上一个额外的操作 foo
可能看起来像这样:
(import (javax.servlet Servlet ServletRequest ServletResponse))
(defprotocol PFoo
(foo [this x y z]))
(reify
Servlet
(service [this ^ServletRequest req ^ServletResponse res]
...)
;; other Servlet methods here...
PFoo
(foo [this x y z]
...))
然后您可以将其包装在一个宏中以提供任何所需的语法糖。请注意,reify
实际上并不关心您在其主体中交错接口(interface)/协议(protocol)名称和方法定义的方式,因此您可以让宏发出
(reify
Servlet PFoo ... ; other interfaces & protocols
(service [...] ...)
(foo [...] ...)
;; other methods
)
如果那样更方便的话。
宏草图采用 servlet 接口(interface)的名称来实现(大概扩展 javax.servlet.Servlet
)并注入(inject)带有一些额外方法的协议(protocol):
(defprotocol PFancyServlet
(do-get [this ...])
(do-post [this ...]))
(defmacro servlet [servlet-iface & meths]
`(reify ~servlet-iface PFancyServlet
~@meths))
meths
需要包括 do-get
和 do-post
以及 servlet-iface
方法;您可以添加一些参数验证以确保是这种情况。调用示例:
(servlet SomeServletInterface
(service [this ...] ...)
;; ...
(do-get [this ...] ...)
(do-post [this ...] ...))
关于java - 将常规 Servlet 编码转变为我的 DSL 的起点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16884878/