经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Java » 查看文章
Java扩展Nginx之一:你好,nginx-clojure
来源:cnblogs  作者:程序员欣宸  时间:2023/7/10 9:58:40  对本文有异议

欢迎访问我的GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos

关于Nginx扩展

  • 以欣宸自己为例,对一个java程序员来说,nginx并不陌生,下图应该是最常见的使用场景了,反向代理:
    在这里插入图片描述
  • 除了反向代理,nginx的模块化机制让nginx具备了更多丰富的特性,例如ngx_http_log_module(日志)、ngx_http_rewrite_module(重定向)等
  • 除了官方模块,还有很多强大第三方模块可以选择,如下图,更多详情参考:https://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模块做个最基本的了解
  • 本文由以下部分构成:
  1. 介绍nginx-clojure
  2. 实战
  3. 验证

介绍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,官网地址是:https://nginx-clojure.github.io
  • 对nginx-clojure的介绍就到这里吧,接下来实战为主

实战功能介绍

  • 尽管nginx-clojure支持很多功能,但本篇以了解为主,还是经典的Hello world,更多精彩内容留给《Java扩展Nginx》系列后面的文章
  • 今天的实战,效果如下图,咱们编写HelloHandler.java并做好配置,然后用浏览器发起请求后,HelloHandler的代码就会被执行,浏览器会收到HelloHandler返回的内容:
    在这里插入图片描述
  • 今天的实战步骤如下图所示:
    在这里插入图片描述
  • 感谢您听我唠叨了这么久,接下来,实战开始

环境信息

  • 这里给出我的实战环境信息供您参考,这个环境可以正常运行所有实战:
  1. 操作系统:macOS Big Sur 11.5.2 (20G95)
  2. JDK:1.8.0_281
  3. Maven:3.8.1

下载集成了nginx-clojure模块的nginx包

  • 咱们要做的第一件事是下载一个特别的nginx,之所以说它特别,是因为它已集成了nginx-clojure模块,开箱即用
  • 下载地址:https://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
  1. ./nginx -v
  2. nginx version: nginx/1.18.0

编码,开发java版handler

  • 接下来开始写代码,先新建一个maven工程(我这里名叫simple-hello),pom.xml中需要配置repository节点,以及唯一的依赖nginx-clojure,如下所示:
  1. <repositories>
  2. <repository>
  3. <id>clojars.org</id>
  4. <url>http://clojars.org/repo</url>
  5. </repository>
  6. </repositories>
  7. <dependencies>
  8. <dependency>
  9. <groupId>nginx-clojure</groupId>
  10. <artifactId>nginx-clojure</artifactId>
  11. <version>0.5.2</version>
  12. </dependency>
  13. </dependencies>
  • 然后新增文件HelloHandler.java,如下所示,代码非常简单,实现NginxJavaRingHandler接口,invoke方法返回的数组中只有三个元素:返回码、响应header的键值对集合、响应body内容:
  1. package com.bolingcavalry.simplehello;
  2. import nginx.clojure.java.ArrayMap;
  3. import nginx.clojure.java.NginxJavaRingHandler;
  4. import java.time.LocalDateTime;
  5. import java.util.Map;
  6. import static nginx.clojure.MiniConstants.CONTENT_TYPE;
  7. import static nginx.clojure.MiniConstants.NGX_HTTP_OK;
  8. /**
  9. * @author zq2599@gmail.com
  10. * @Title: 产生内容的handler
  11. * @Package
  12. * @Description:
  13. * @date 2/1/22 12:41 PM
  14. */
  15. public class HelloHandler implements NginxJavaRingHandler {
  16. @Override
  17. public Object[] invoke(Map<String, Object> request) {
  18. return new Object[] {
  19. NGX_HTTP_OK, //http status 200
  20. ArrayMap.create(CONTENT_TYPE, "text/plain"), //headers map
  21. "Hello, Nginx clojure! " + LocalDateTime.now() //response body can be string, File or Array/Collection of them
  22. };
  23. }
  24. }
  • 至此,编码完成,欣宸精通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类:
  1. location /java {
  2. content_handler_type 'java';
  3. content_handler_name 'com.bolingcavalry.simplehello.HelloHandler';
  4. }
  • 修改后,完整的nginx.conf内容如下,可见有很多java相关的配置,在本篇咱们都保持不动,留待后面的文章细细解锁:
  1. ###you can uncomment next two lines for easy debug
  2. ###Warning: if master_process is off, there will be only one nginx worker running. Only use it for debug propose.
  3. #daemon off;
  4. #master_process off;
  5. #user nobody;
  6. worker_processes 1;
  7. #error_log logs/error.log;
  8. #error_log logs/error.log notice;
  9. #error_log logs/error.log info;
  10. #pid logs/nginx.pid;
  11. events {
  12. worker_connections 1024;
  13. }
  14. http {
  15. include mime.types;
  16. default_type application/octet-stream;
  17. #log_format main '$remote_addr - $remote_user [$time_local] "$request" '
  18. # '$status $body_bytes_sent "$http_referer" '
  19. # '"$http_user_agent" "$http_x_forwarded_for"';
  20. #access_log logs/access.log main;
  21. sendfile on;
  22. #tcp_nopush on;
  23. #keepalive_timeout 0;
  24. keepalive_timeout 65;
  25. #gzip on;
  26. jvm_path auto;
  27. ### Set my app jars and resources, it must include nginx-clojure runtime jar,e.g. nginx-clojure-0.5.1.jar and
  28. ### for clojure user clojure runtime jar is also needed.
  29. ### See http://nginx-clojure.github.io/directives.html#jvm_classpath
  30. jvm_classpath "libs/*:jars/*";
  31. ###jvm heap memory
  32. #jvm_options "-Xms1024m";
  33. #jvm_options "-Xmx1024m";
  34. #for enable java remote debug uncomment next two lines
  35. #jvm_options "-Xdebug";
  36. #jvm_options "-Xrunjdwp:server=y,transport=dt_socket,address=840#{pno},suspend=n";
  37. ###threads number for request handler thread pool on jvm, default is 0.
  38. ###check more details from
  39. #jvm_workers 8;
  40. server {
  41. listen 8080;
  42. server_name localhost;
  43. #charset koi8-r;
  44. #access_log logs/host.access.log main;
  45. location / {
  46. root html;
  47. index index.html index.htm;
  48. }
  49. #error_page 404 /404.html;
  50. # redirect server error pages to the static page /50x.html
  51. #
  52. error_page 500 502 503 504 /50x.html;
  53. location = /50x.html {
  54. root html;
  55. }
  56. location /clojure {
  57. handler_type 'clojure';
  58. handler_code '
  59. (fn[req]
  60. {
  61. :status 200,
  62. :headers {"content-type" "text/plain"},
  63. :body "Hello Clojure & Nginx!"
  64. })
  65. ';
  66. }
  67. location /java {
  68. content_handler_type 'java';
  69. content_handler_name 'com.bolingcavalry.simplehello.HelloHandler';
  70. }
  71. # location /groovy {
  72. # handler_type 'groovy';
  73. # handler_code '
  74. # import nginx.clojure.java.NginxJavaRingHandler;
  75. # import java.util.Map;
  76. # public class HelloGroovy implements NginxJavaRingHandler {
  77. # public Object[] invoke(Map<String, Object> request){
  78. # return [200, //http status 200
  79. # ["Content-Type":"text/html"], //headers map
  80. # "Hello, Groovy & Nginx!"]; //response body can be string, File or Array/Collection of them
  81. # }
  82. # }
  83. # ';
  84. # }
  85. #
  86. }
  87. }

7. 启动nginx

  • 启动命令很简单,在nginx-clojure-0.5.2目录下执行./nginx
  • 如果启动失败了,请打开nginx-clojure-0.5.2/logs/error.log查看问题,例如我这里遇到过端口占用导致启动失败:
  1. 2022/02/02 17:45:07 [emerg] 27703#0: bind() to 0.0.0.0:8080 failed (48: Address already in use)
  2. 2022/02/02 17:45:07 [emerg] 27703#0: bind() to 0.0.0.0:8080 failed (48: Address already in use)
  3. 2022/02/02 17:45:07 [emerg] 27703#0: bind() to 0.0.0.0:8080 failed (48: Address already in use)
  4. 2022/02/02 17:45:07 [emerg] 27703#0: bind() to 0.0.0.0:8080 failed (48: Address already in use)
  5. 2022/02/02 17:45:07 [emerg] 27703#0: bind() to 0.0.0.0:8080 failed (48: Address already in use)
  6. 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的强大功能,欣宸原创,期待您的关注

源码下载

名称 链接 备注
项目主页 https://github.com/zq2599/blog_demos 该项目在GitHub上的主页
git仓库地址(https) https://github.com/zq2599/blog_demos.git 该项目源码的仓库地址,https协议
git仓库地址(ssh) git@github.com:zq2599/blog_demos.git 该项目源码的仓库地址,ssh协议
  • 这个git项目中有多个文件夹,本篇的源码在nginx-clojure-tutorials文件夹下,如下图红框所示:
    在这里插入图片描述

欢迎关注博客园:程序员欣宸

学习路上,你不孤单,欣宸原创一路相伴...

原文链接:https://www.cnblogs.com/bolingcavalry/p/17537117.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号