Java擴充套件Nginx之一:你好,nginx-clojure
一起養成寫作習慣!這是我參與「掘金日新計劃 · 4 月更文挑戰」的第14天,點選檢視活動詳情。
歡迎訪問我的GitHub
這裡分類和彙總了欣宸的全部原創(含配套原始碼):http://github.com/zq2599/blog_demos
關於Nginx擴充套件
- 以欣宸自己為例,對一個java程式設計師來說,nginx並不陌生,下圖應該是最常見的使用場景了,反向代理:
- 除了反向代理,nginx的模組化機制讓nginx具備了更多豐富的特性,例如ngx_http_log_module(日誌)、ngx_http_rewrite_module(重定向)等
- 除了官方模組,還有很多強大第三方模組可以選擇,如下圖,更多詳情參考:http://www.nginx.com/resources/wiki/modules/
- 如此看來,在nginx上做二次開發並非神祕高深莫測,我們也可以按照自己的需要去定製和擴充套件nginx的功能
- 然而,開啟官方的開發文件,畫風如下:
- nginx的自定義模組使用C語言開發的,然而,欣宸只是個精通CRUD的Java程式設計師啊
- 幸好有了nginx-clojure模組,它支援使用Java對Nginx進行功能擴充套件:
- 至此,聰明的您應該猜到《Java擴充套件Nginx》系列的核心內容了:學習nginx-clojure模組,從入門到精通,解鎖Clojure的強大能力,通過豐富的實戰與大家一起掌握用Java擴充套件Nginx的技術
本篇概覽
- 作為《Java擴充套件Nginx》系列的開篇,本文將延續欣宸原創的風格:用最少的時間和最簡潔的功能,與大家一同對nginx-clojure模組做個最基本的瞭解
- 本文由以下部分構成:
- 介紹nginx-clojure
- 實戰
- 驗證
介紹nginx-clojure
- nginx-clojure是個第三方Nginx模組,官方的介紹是Nginx module for embedding Clojure / Java / Groovy programs, typically those Ring based handlers
- nginx-clojure模組支援嵌入式Clojure(閉包)、Java、Groovy等基於Ring的處理器(handler),那什麼是Ring呢?
- Ring 在 Clojure 中是一個構建 Web 應用的底層介面和庫. 它和 Ruby 的 Rack, Python 裡面的WSGI 或者 Java Servlet 規範相似
- 從java開發者角度來看,就是開發NginxJavaRingHandler的實現類,然後該類可以在nginx-clojure模組中被執行
- nginx-clojure的最新版本是v0.5.2,官網地址是:http://nginx-clojure.github.io
- 對nginx-clojure的介紹就到這裡吧,接下來實戰為主
實戰功能介紹
- 儘管nginx-clojure支援很多功能,但本篇以瞭解為主,還是經典的Hello world,更多精彩內容留給《Java擴充套件Nginx》系列後面的文章
- 今天的實戰,效果如下圖,咱們編寫HelloHandler.java並做好配置,然後用瀏覽器發起請求後,HelloHandler的程式碼就會被執行,瀏覽器會收到HelloHandler返回的內容:
- 今天的實戰步驟如下圖所示:
- 感謝您聽我嘮叨了這麼久,接下來,實戰開始
環境資訊
- 這裡給出我的實戰環境資訊供您參考,這個環境可以正常執行所有實戰:
- 作業系統:macOS Big Sur 11.5.2 (20G95)
- JDK:1.8.0_281
- Maven:3.8.1
下載集成了nginx-clojure模組的nginx包
- 咱們要做的第一件事是下載一個特別的nginx,之所以說它特別,是因為它已集成了nginx-clojure模組,開箱即用
- 下載地址:http://sourceforge.net/projects/nginx-clojure/files/ ,如下圖紅框,我這裡選擇的是最新的0.5.2版本:
解壓nginx包
- 下載完畢後,解壓,得到名為nginx-clojure-0.5.2的資料夾,裡面的內容如下:
- 接下來根據您的作業系統對可執行檔案做重新命名,我這邊是macOS,所以把nginx-macosx重新命名為nginx,如果是linux,把nginx-linux-64重新命名為nginx,如果是windows,就把nginx-win64.exe重新命名為nginx.exe
- 上述重新命名操作是nginx-clojure官方推薦的,統一可執行檔名,這樣執行文件中的命令就統一了
- 執行命令./nginx -v,控制檯響應如下,可見nginx版本是1.18.0:
shell ./nginx -v nginx version: nginx/1.18.0
編碼,開發java版handler
- 接下來開始寫程式碼,先新建一個maven工程(我這裡名叫simple-hello),pom.xml中需要配置repository節點,以及唯一的依賴nginx-clojure,如下所示:
```xml
clojars.org http://clojars.org/repo
- 然後新增檔案<font color="blue">HelloHandler.java</font>,如下所示,程式碼非常簡單,實現NginxJavaRingHandler介面,invoke方法返回的陣列中只有三個元素:返回碼、響應header的鍵值對集合、響應body內容:
java
public class HelloHandler implements NginxJavaRingHandler {
@Override
public Object[] invoke(Map<String, Object> request) {
return new Object[] {
NGX_HTTP_OK, //http status 200
ArrayMap.create(CONTENT_TYPE, "text/plain"), //headers map
"Hello, Nginx clojure! " + LocalDateTime.now() //response body can be string, File or Array/Collection of them
};
}
} ``` - 至此,編碼完成,欣宸精通Hello World果然並非空穴來風...
編譯,生成jar
- 在pom.xml所在目錄執行命令mvn clean package -U,會在target目錄下生成jar包,只有3K大小:
jar放入nginx的jars目錄
- 將前面生成的simple-hello-1.0-SNAPSHOT.jar檔案放入下圖紅框的jars資料夾內:
修改nginx的配置
- 開啟nginx-clojure-0.5.2/conf/nginx.conf檔案,在server配置中增加一個location配置,內容如下,指定了handler型別,以及對應的java類:
bash location /java { content_handler_type 'java'; content_handler_name 'com.bolingcavalry.simplehello.HelloHandler'; }
- 修改後,完整的nginx.conf內容如下,可見有很多java相關的配置,在本篇咱們都保持不動,留待後面的文章細細解鎖: ```bash
you can uncomment next two lines for easy debug
Warning: if master_process is off, there will be only one nginx worker running. Only use it for debug propose.
daemon off;
master_process off;
user nobody;
worker_processes 1;
error_log logs/error.log;
error_log logs/error.log notice;
error_log logs/error.log info;
pid logs/nginx.pid;
events { worker_connections 1024; }
http { include mime.types; default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
jvm_path auto;
### Set my app jars and resources, it must include nginx-clojure runtime jar,e.g. nginx-clojure-0.5.1.jar and
### for clojure user clojure runtime jar is also needed.
### See http://nginx-clojure.github.io/directives.html#jvm_classpath
jvm_classpath "libs/*:jars/*";
###jvm heap memory
#jvm_options "-Xms1024m";
#jvm_options "-Xmx1024m";
#for enable java remote debug uncomment next two lines
#jvm_options "-Xdebug";
#jvm_options "-Xrunjdwp:server=y,transport=dt_socket,address=840#{pno},suspend=n";
###threads number for request handler thread pool on jvm, default is 0.
###check more details from
#jvm_workers 8;
server {
listen 8080;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
location /clojure {
handler_type 'clojure';
handler_code '
(fn[req]
{
:status 200,
:headers {"content-type" "text/plain"},
:body "Hello Clojure & Nginx!"
})
';
}
location /java {
content_handler_type 'java';
content_handler_name 'com.bolingcavalry.simplehello.HelloHandler';
}
location /groovy {
handler_type 'groovy';
handler_code '
import nginx.clojure.java.NginxJavaRingHandler;
import java.util.Map;
public class HelloGroovy implements NginxJavaRingHandler {
public Object[] invoke(Map request){
return [200, //http status 200
["Content-Type":"text/html"], //headers map
"Hello, Groovy & Nginx!"]; //response body can be string, File or Array/Collection of them
}
}
';
}
}
} ```
7. 啟動nginx
- 啟動命令很簡單,在nginx-clojure-0.5.2目錄下執行./nginx
- 如果啟動失敗了,請開啟nginx-clojure-0.5.2/logs/error.log檢視問題,例如我這裡遇到過端口占用導致啟動失敗:
shell 2022/02/02 17:45:07 [emerg] 27703#0: bind() to 0.0.0.0:8080 failed (48: Address already in use) 2022/02/02 17:45:07 [emerg] 27703#0: bind() to 0.0.0.0:8080 failed (48: Address already in use) 2022/02/02 17:45:07 [emerg] 27703#0: bind() to 0.0.0.0:8080 failed (48: Address already in use) 2022/02/02 17:45:07 [emerg] 27703#0: bind() to 0.0.0.0:8080 failed (48: Address already in use) 2022/02/02 17:45:07 [emerg] 27703#0: bind() to 0.0.0.0:8080 failed (48: Address already in use) 2022/02/02 17:45:07 [emerg] 27703#0: still could not bind()
8. 驗證
- 開啟postman驗證服務是否正常,請求地址是http://127.0.0.1:8080/java
- 響應如下圖所示,符合預期,返回的就是咱們定製的HelloHandler的內容
- 至此,nginx-clojure的入門操作就完成的,雖然寥寥幾行程式碼,但卻給java程式設計師打開了一扇窗:用咱們熟悉的技術去擴充套件nginx,參與到nginx豐富的生態環境中
方向對嗎?個人的一點想法
- 把java程式碼寫在nginx上,讓nginx與業務耦合的可能性變大,經驗豐富的您一定會發現這是個危險的趨勢,畢竟nginx已經接近後臺服務的最外層了,穩定是首要考慮的,正常情況下,下圖這種將nginx作為反向代理,業務功能獨立部署的方式才是生產環境常用方案:
- 這麼看來,在nginx上寫java程式碼是否合適呢?欣宸給不出權威答案,但是可以從大神的作品中得到靈感
- 開濤大神的《跟我學Nginx+Lua開發》講述瞭如何用OpenResty在Nginx上用Lua進行開發,適用於web應用、接入閘道器、Web防火牆、快取伺服器等場景下,並且在實體書《億級流量網站架構核心技術》也有詳細說明,例如京東商品詳情頁,就是在nginx上讀取快取直接返回的
- 綜上所訴,欣宸不會因為學習了這個技術,就把業務邏輯全部在nginx上實現,但是在快取、鑑權等場景,可以考慮用熟悉的java在nginx上實現
- 至此,《Java擴充套件Nginx》的開篇就完成了,簡簡單單的實戰,讓我們看到了java在nginx領域大顯神通的可能,接下來文章,會繼續深入學習nginx-clojure的強大功能,欣宸原創,期待您的關注
原始碼下載
- 《Java擴充套件Nginx》的完整原始碼可在GitHub下載到,地址和連結資訊如下表所示(http://github.com/zq2599/blog_demos):
| 名稱 | 連結 | 備註| | :-------- | :----| :----| | 專案主頁| http://github.com/zq2599/blog_demos | 該專案在GitHub上的主頁 | | git倉庫地址(https)| http://github.com/zq2599/blog_demos.git | 該專案原始碼的倉庫地址,https協議 | | git倉庫地址(ssh)| [email protected]:zq2599/blog_demos.git | 該專案原始碼的倉庫地址,ssh協議 |
- 這個git專案中有多個資料夾,本篇的原始碼在nginx-clojure-tutorials資料夾下,如下圖紅框所示:
歡迎關注掘金:程式設計師欣宸
- 瀏覽器上寫程式碼,4核8G微軟伺服器免費用,Codespaces真香
- Java擴充套件Nginx之三:基礎配置項
- Java擴充套件Nginx之一:你好,nginx-clojure
- JavaCV的攝像頭實戰之十四:口罩檢測
- JavaCV人臉識別三部曲之二:訓練
- JavaCV人臉識別三部曲之一:視訊中的人臉儲存為圖片
- JavaCV的攝像頭實戰之八:人臉檢測
- 超詳細的編碼實戰,讓你的springboot應用識別圖片中的行人、汽車、狗子、喵星人(JavaCV YOLO4)
- Java應用日誌如何與Jaeger的trace關聯
- Spring Cloud Gateway實戰之五:內建filter
- Spring Cloud Gateway的斷路器(CircuitBreaker)功能
- Java版流媒體編解碼和影象處理(JavaCPP FFmpeg)
- DL4J實戰之六:圖形化展示訓練過程
- 純淨Ubuntu16安裝CUDA(9.1)和cuDNN
- disruptor筆記之六:常見場景
- Spring Cloud Gateway過濾器精確控制異常返回(分析篇)
- disruptor筆記之四:事件消費知識點小結
- disruptor筆記之二:Disruptor類分析
- disruptor筆記之一:快速入門
- Spring Native實戰(暢快體驗79毫秒啟動springboot應用)