欢迎访问我的GitHub

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

本篇概览

  • 今天咱们以Java程序员的视角,来聊聊如何用Java来扩展Nginx的能力,全文由以下内容组成:
  1. 什么是Nginx
  2. 什么是Nginx扩展
  3. 扩展Nginx,意义何在?
  4. 想用Java扩展Nginx会有问题吗?
  5. 主角登场:nginx-clojure模块,让Java扩展Nginx成为显示
  • 总的来说这是一篇从概念到实践的入门文章,接下来,一起开始愉快的nginx-clojure之旅吧!

关于Nginx

  • 以欣宸自己为例,nginx对java程序员来说并不陌生,下图应该是最常见的使用场景了:反向代理

关于Nginx扩展

  • 除了反向代理,nginx的模块化机制让nginx具备了更多丰富的特性,例如ngx_http_log_module(日志)、ngx_http_rewrite_module(重定向)等
  • 除了官方模块,还有很多强大第三方模块可以选择,如下图,更多详情参考:https://www.nginx.com/resources/wiki/modules/

  • 大名鼎鼎的OpenResty就是基于 Nginx 扩展的,用Lua做二次开发web功能,得到了广泛的应用
  • 如此看来,在nginx上做二次开发并非神秘高深莫测,我们也可以按照自己的需要去定制和扩展nginx的功能
  • 作为一名Java程序员,自然就想到了:可以用Java去扩展Nginx的能力吗?

为什么要用java对nginx扩展?

  • 把java代码写在nginx上,让nginx与业务耦合的可能性变大,经验丰富的您一定会发现这是个危险的趋势,毕竟nginx已经接近后台服务的最外层了,稳定是首要考虑的,正常情况下,下图这种用法才是生产环境的常见fang方案:将nginx作为反向代理,业务功能独立部署

  • 这么看来,在nginx上写java代码是否合适呢?欣宸给不出权威答案,但是可以从大神的作品中得到启示
  • 开涛大神的《跟我学Nginx+Lua开发》讲述了如何用OpenResty在Nginx上用Lua进行开发,适用于web应用、接入网关、Web防火墙、缓存服务器等场景下,并且在实体书《亿级流量网站架构核心技术》也有详细说明,例如京东商品详情页,就是在nginx上读取缓存直接返回的
  • 综上所述,欣宸不会因为学习了这个技术,就把业务逻辑全部在nginx上实现,但是在缓存、鉴权等场景,可以考虑用熟悉的java在nginx上实现

Java程序员的尴尬

  • 定制Nginx,打造高性能Web服务,带着这个美好憧憬,我打开了有关模块开发的Nginx官方资料
  • 然后,画风开始剧变,而且是朝着我不想面对的方向,如下图

  • 模块开发用的居然是C语言!然而,欣宸只是个精通CRUD的Java程序员啊
  • 这可怎么办?随手打开一个网页就让梦想破灭?

nginx-clojure,让Java扩展nginx成为现实

  • 经过一番搜索,终于找到了nginx-clojure模块,如下图,是它让java扩展nginx成为现实

  • nginx-clojure的作用很好理解:OpenResty支持用Lua扩展nginx,nginx-clojure支持用Java扩展nginx
  • nginx-clojure的作用很好理解:OpenResty支持用Lua扩展nginx,nginx-clojure支持用Java扩展nginx

关于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支持很多功能,但是篇幅所限,因此本篇以了解为主,还是经典的Hello world,更多精彩内容留给后续的系列文章
  • 今天的实战效果如下图,咱们编写HelloHandler.java并在nginx做好配置,然后用浏览器发起请求后,HelloHandler的代码就会被执行,浏览器会收到HelloHandler返回的内容,这就证实了java代码可以在nginx上运行:

  • 为了实现上述功能,接下来的操作步骤如下图:

  • 感谢您听我唠叨了这么久,接下来,实战开始

环境信息

  • 这里给出我的实战环境信息供您参考,这个环境可以正常运行所有实战:
  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:
./nginx -v
nginx version: nginx/1.18.0

编码,开发java版handler

  • 接下来开始写代码,先新建一个maven工程(我这里名叫simple-hello),pom.xml中需要配置repository节点,以及唯一的依赖nginx-clojure,如下所示:
<repositories>
<repository>
<id>clojars.org</id>
<url>http://clojars.org/repo</url>
</repository>
</repositories> <dependencies>
<dependency>
<groupId>nginx-clojure</groupId>
<artifactId>nginx-clojure</artifactId>
<version>0.5.2</version>
</dependency>
</dependencies>
  • 然后新增文件HelloHandler.java,如下所示,代码非常简单,实现NginxJavaRingHandler接口,invoke方法返回的数组中只有三个元素:返回码、响应header的键值对集合、响应body内容:
package com.bolingcavalry.simplehello;

import nginx.clojure.java.ArrayMap;
import nginx.clojure.java.NginxJavaRingHandler; import java.time.LocalDateTime;
import java.util.Map; import static nginx.clojure.MiniConstants.CONTENT_TYPE;
import static nginx.clojure.MiniConstants.NGX_HTTP_OK; /**
* @author zq2599@gmail.com
* @Title: 产生内容的handler
* @Package
* @Description:
* @date 2/1/22 12:41 PM
*/
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类:
location /java {
content_handler_type 'java';
content_handler_name 'com.bolingcavalry.simplehello.HelloHandler';
}
  • 修改后,完整的nginx.conf内容如下,可见有很多java相关的配置,在本篇咱们都保持不动,留待后面的文章解锁:
###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<String, Object> 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
# }
# }
# ';
# }
#
}
}

启动nginx

  • 启动命令很简单,在nginx-clojure-0.5.2目录下执行./nginx
  • 如果启动失败了,请打开nginx-clojure-0.5.2/logs/error.log查看问题,例如我这里遇到过端口占用导致启动失败:
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()

验证

  • 打开postman验证服务是否正常,请求地址是http://127.0.0.1:8080/java
  • 响应如下图所示,符合预期,返回的就是咱们定制的HelloHandler的内容

  • 至此,nginx-clojure的入门操作就完成了,虽然寥寥几行代码,但却给java程序员打开了一扇窗:用咱们熟悉的技术去扩展nginx,打造更符合业务的web服务器,以最短链路完成web响应
  • 本篇只是nginx-clojure之旅的开端,先对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文件夹下,如下图红框所示:

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

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

精选版:用Java扩展Nginx(nginx-clojure 入门)的更多相关文章

  1. docker学习(6) docker中搭建java服务及nginx反向代理

    先看下容器规划: 上图中mysql容器的搭建见上篇博客,service1/2为java rest service,创建脚本如下: docker run -d -h service1 \ -v /Use ...

  2. 【工具-Nginx】从入门安装到高可用集群搭建

    文章已收录至https://lichong.work,转载请注明原文链接. ps:欢迎关注公众号"Fun肆编程"或添加我的私人微信交流经验 一.Nginx安装配置及常用命令 1.环 ...

  3. OpenResty(Nginx+Lua)开发入门

    Nginx入门 本文目的是学习Nginx+Lua开发,对于Nginx基本知识可以参考如下文章: nginx启动.关闭.重启 http://www.cnblogs.com/derekchen/archi ...

  4. Nginx开发从入门到精通 学习目录分享学习 (阿里著作)

    Nginx开发从入门到精通   缘起 nginx由于出色的性能,在世界范围内受到了越来越多人的关注,在淘宝内部它更是被广泛的使用,众多的开发以及运维同学都迫切的想要了解nginx模块的开发以及它的内部 ...

  5. 【转】Nginx模块开发入门

    转自: http://kb.cnblogs.com/page/98352/ 结论:对Nginx模块开发入门做了一个helloworld的示例,简单易懂.也有一定的深度.值得一看. Nginx模块开发入 ...

  6. Nginx模块开发入门

    前言 Nginx是当前最流行的HTTP Server之一,根据W3Techs的统计,目前世界排名(根据Alexa)前100万的网站中,Nginx的占有率为6.8%.与Apache相比,Nginx在高并 ...

  7. [转] Nginx模块开发入门

    前言 Nginx是当前最流行的HTTP Server之一,根据W3Techs的统计,目前世界排名(根据Alexa)前100万的网站中,Nginx的占有率为6.8%.与Apache相比,Nginx在高并 ...

  8. Nginx模块开发入门(转)

    前言 Nginx是当前最流行的HTTP Server之一,根据W3Techs的统计,目前世界排名(根据Alexa)前100万的网站中,Nginx的占有率为6.8%.与Apache相比,Nginx在高并 ...

  9. Nginx模块开发入门(转)

    前言 Nginx是当前最流行的HTTP Server之一,根据W3Techs的统计,目前世界排名(根据Alexa)前100万的网站中,Nginx的占有率为6.8%.与Apache相比,Nginx在高并 ...

  10. java面试题—精选30道Java笔试题解答(二)

    摘要: java面试题-精选30道Java笔试题解答(二) 19. 下面程序能正常运行吗() public class NULL { public static void haha(){ System ...

随机推荐

  1. 包含引用类型字段的自定义结构体,能作为map的key吗

    1. 引言 在 Go 语言中,map是一种内置的数据类型,它提供了一种高效的方式来存储和检索数据.map是一种无序的键值对集合,其中每个键与一个值相关联.使用 map 数据结构可以快速地根据键找到对应 ...

  2. python利用subprocess执行shell命令

    subprocess以及常用的封装函数 运行python的时候,我们都是在创建并运行一个进程.像Linux进程那样,一个进程可以fork一个子进程,并让这个子进程exec另外一个程序.在Python中 ...

  3. 实用的windows快捷键

    Alt+F4 关闭窗口 win+D 显示桌面 win+Tab 切换窗口 Alt+Tab 应用之间的切换 win+E 打开我的电脑 Ctrl+Shift+Esc 打开任务管理器 Home 回到行首 En ...

  4. [汽车]车架号(VIN)的设计与规范

    1 车架号概述 VIN是英文Vehicle Identification Number(车辆识别代码)的缩写,也就是我们平时所说的车架号.大架号. 总共由17位字符组成,是汽车唯一的身份识别信息,好比 ...

  5. Python之Excel表格数据处理

    正式开讲之前,我们需要先了解几个基本的知识点:1.Python字典(Dictionary) 的setdefault()方法描述:如果键不存在于字典中,将会添加键并将值设为默认值.语法:dict.set ...

  6. 基于uniapp+vite4+vue3搭建跨端项目|uni-app+uview-plus模板

    最近得空学习了下uniapp结合vue3搭建跨端项目.之前也有使用uniapp开发过几款聊天/仿抖音/后台管理等项目,但都是基于vue2开发.随着vite.js破局出圈,越来越多的项目偏向于vue3开 ...

  7. 通过安装GVM 安装GO 操作步骤

    转载请注明出处: 1.GVM GVM是Go Version Manager的缩写,是一个用于管理Go语言版本的工具.通过GVM,我们可以轻松地安装.切换和卸载不同版本的Go语言.GVM会在用户的hom ...

  8. HLS AES加密

    HLS AES加密 HLS AES加密介绍 HLS AES加密是一种用于保护HLS流内容安全的加密技术.它通过将HLS媒体文件进行分段,并使用AES加密算法对每个片段进行加密,从而防止未经授权的访问和 ...

  9. LeetCode 双周赛 107(2023/06/24)滑动窗口与离散化

    本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 和 [BaguTree Pro] 知识星球提问. 往期回顾:LeetCode 单周赛第 348 场 · 数位 DP ...

  10. [python] 基于matplotlib-scalebar库绘制比例尺

    matplotlib-scalebar是一个Python库,用于在matplotlib图形中添加比例尺.它允许用户指定比例尺的大小.位置.字体和颜色,以及比例尺的单位.该库支持不同的比例尺单位,例如米 ...