前言
大家好,我是老马。很高兴遇到你。
我们为 java 开发者实现了 java 版本的 nginx
如果你想知道 servlet 如何处理的,可以参考我的另一个项目:
手写从零实现简易版 tomcat minicat
手写 nginx 系列
如果你对 nginx 原理感兴趣,可以阅读:
从零手写实现 nginx-01-为什么不能有 java 版本的 nginx?
从零手写实现 nginx-03-nginx 基于 Netty 实现
从零手写实现 nginx-04-基于 netty http 出入参优化处理
从零手写实现 nginx-05-MIME类型(Multipurpose Internet Mail Extensions,多用途互联网邮件扩展类型)
从零手写实现 nginx-12-keep-alive 连接复用
从零手写实现 nginx-13-nginx.conf 配置文件介绍
从零手写实现 nginx-14-nginx.conf 和 hocon 格式有关系吗?
从零手写实现 nginx-15-nginx.conf 如何通过 java 解析处理?
从零手写实现 nginx-16-nginx 支持配置多个 server
从零手写实现 nginx-18-nginx 请求头+响应头操作
从零手写实现 nginx-20-nginx 占位符 placeholder
从零手写实现 nginx-21-nginx modules 模块信息概览
从零手写实现 nginx-22-nginx modules 分模块加载优化
从零手写实现 nginx-23-nginx cookie 的操作处理
从零手写实现 nginx-26-nginx rewrite 指令
从零手写实现 nginx-27-nginx return 指令
从零手写实现 nginx-28-nginx error_pages 指令
从零手写实现 nginx-29-nginx try_files 指令
从零手写实现 nginx-30-nginx proxy_pass upstream 指令
从零手写实现 nginx-31-nginx load-balance 负载均衡
从零手写实现 nginx-32-nginx load-balance 算法 java 实现
从零手写实现 nginx-33-nginx http proxy_pass 测试验证
从零手写实现 nginx-34-proxy_pass 配置加载处理
从零手写实现 nginx-35-proxy_pass netty 如何实现?
目标
上一节我们定义了配置的标准 POJO
这一节课我们来把 nginx.conf 文件解析为标准的 pojo
实现思路
通过三方库直接解析处理配置文件。
核心代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214package com.github.houbb.nginx4j.config.load;
import com.github.houbb.heaven.util.lang.StringUtil;
import com.github.houbb.heaven.util.util.CollectionUtil;
import com.github.houbb.nginx4j.bs.NginxUserConfigBs;
import com.github.houbb.nginx4j.bs.NginxUserServerConfigBs;
import com.github.houbb.nginx4j.config.NginxUserConfig;
import com.github.houbb.nginx4j.config.NginxUserServerConfig;
import com.github.houbb.nginx4j.constant.NginxUserConfigDefaultConst;
import com.github.houbb.nginx4j.constant.NginxUserServerConfigDefaultConst;
import com.github.odiszapc.nginxparser.NgxBlock;
import com.github.odiszapc.nginxparser.NgxConfig;
import com.github.odiszapc.nginxparser.NgxEntry;
import com.github.odiszapc.nginxparser.NgxParam;
import java.io.IOException;
import java.util.List;
/**
* @since 0.13.0
*/
public class NginxUserConfigLoaderConfigFile extends AbstractNginxUserConfigLoader {
private final String filePath;
public NginxUserConfigLoaderConfigFile(String filePath) {
this.filePath = filePath;
}
protected void fillBasicInfo(final NginxUserConfigBs configBs,
final NgxConfig conf) {
// 基本信息
configBs.httpPid(getHttpPid(conf));
}
private String getHttpPid(final NgxConfig conf) {
// 基本信息
NgxParam pidParam = conf.findParam("pid");
if(pidParam != null) {
return pidParam.getValue();
}
return NginxUserConfigDefaultConst.HTTP_PID;
}
/**
* <pre>
* listen 80; # 监听80端口
* server_name example.com; # 服务器域名
*
* # 单独为这个 server 启用 sendfile
* sendfile on;
*
* # 静态文件的根目录
* root /usr/share/nginx/html; # 静态文件存放的根目录
* index index.html index.htm; # 默认首页
*
* # 如果需要为这个 server 单独配置 gzip,可以覆盖全局配置
* gzip on;
* gzip_disable "msie6";
* gzip_vary on;
* gzip_proxied any;
* gzip_comp_level 6;
* gzip_buffers 16 8k;
* gzip_http_version 1.1;
* gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
*
* </pre>
* @param configBs 配置
* @param conf 文件信息
*/
protected void fillServerInfo(final NginxUserConfigBs configBs,
final NgxConfig conf) {
// 首先获取 block
List<NgxEntry> servers = conf.findAll(NgxConfig.BLOCK, "http", "server"); // 示例3
if(CollectionUtil.isNotEmpty(servers)) {
for (NgxEntry entry : servers) {
NginxUserServerConfigBs serverConfigBs = NginxUserServerConfigBs.newInstance();
NgxBlock serverBlock = (NgxBlock) entry;
String name = serverBlock.getName();
int httpServerPort = getHttpServerListen(conf, serverBlock);
String httpServerName = getHttpServerName(conf, serverBlock);
String httpServerRoot = getHttpServerRoot(conf, serverBlock);
List<String> httpIndexList = getHttpServerIndexList(conf, serverBlock);
// sendfile on;
String sendFile = getHttpServerSendFile(conf, serverBlock);
//gzip
String gzip = getHttpServerGzip(conf, serverBlock);
long gzipMinLen = getHttpServerGzipMinLen(conf, serverBlock);
List<String> gzipTypes = getHttpServerGzipTypes(conf, serverBlock);
serverConfigBs.httpServerName(httpServerName)
.httpServerListen(httpServerPort)
.httpServerRoot(httpServerRoot)
.httpServerIndexList(httpIndexList)
.sendFile(sendFile)
.gzip(gzip)
.gzipMinLength(gzipMinLen)
.gzipTypes(gzipTypes);
NginxUserServerConfig serverConfig = serverConfigBs.build();
configBs.addServerConfig(httpServerPort, httpServerName, serverConfig);
}
}
}
private List<String> getHttpServerGzipTypes(final NgxConfig conf, final NgxBlock serverBlock) {
// value
NgxParam param = serverBlock.findParam("gzip_types");
if(param != null) {
return StringUtil.splitToList(param.getValue(), " ");
}
return NginxUserServerConfigDefaultConst.gzipTypes;
}
private long getHttpServerGzipMinLen(final NgxConfig conf, final NgxBlock serverBlock) {
// value
NgxParam param = serverBlock.findParam("gzip_min_len");
if(param != null) {
return Long.valueOf(param.getValue());
}
return NginxUserServerConfigDefaultConst.gzipMinLength;
}
private String getHttpServerGzip(final NgxConfig conf, final NgxBlock serverBlock) {
// value
NgxParam param = serverBlock.findParam("gzip");
if(param != null) {
return param.getValue();
}
return NginxUserServerConfigDefaultConst.gzip;
}
private List<String> getHttpServerIndexList(final NgxConfig conf, final NgxBlock serverBlock) {
// value
NgxParam param = serverBlock.findParam("index");
if(param != null) {
return StringUtil.splitToList(param.getValue(), " ");
}
return NginxUserServerConfigDefaultConst.httpServerIndexList;
}
private String getHttpServerSendFile(final NgxConfig conf, final NgxBlock serverBlock) {
// value
NgxParam param = serverBlock.findParam("sendfile");
if(param != null) {
return param.getValue();
}
return NginxUserServerConfigDefaultConst.sendFile;
}
private String getHttpServerRoot(final NgxConfig conf, final NgxBlock serverBlock) {
// value
NgxParam param = serverBlock.findParam("root");
if(param != null) {
return param.getValue();
}
return NginxUserServerConfigDefaultConst.httpServerRoot;
}
private int getHttpServerListen(final NgxConfig conf, final NgxBlock serverBlock) {
// value
NgxParam listenParam = serverBlock.findParam("listen");
if(listenParam != null) {
String value = listenParam.getValue();
List<String> valueList = StringUtil.splitToList(value, " ");
return Integer.parseInt(valueList.get(0));
}
return NginxUserServerConfigDefaultConst.httpServerListen;
}
private String getHttpServerName(final NgxConfig conf, final NgxBlock serverBlock) {
// value
NgxParam param = serverBlock.findParam("server_name");
if(param != null) {
return param.getValue();
}
return NginxUserServerConfigDefaultConst.httpServerName;
}
@Override
protected NginxUserConfig doLoad() {
NgxConfig conf = null;
try {
NginxUserConfigBs configBs = NginxUserConfigBs.newInstance();
conf = NgxConfig.read(filePath);
//1. basic
fillBasicInfo(configBs, conf);
//2. server 信息
fillServerInfo(configBs, conf);
// 返回
return configBs.build();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
启动类
1
2
3
4
5
6NginxUserConfig nginxUserConfig = NginxUserConfigLoaders.configFile("D:\\github\\nginx4j\\src\\main\\resources\\nginx.conf").load();
Nginx4jBs.newInstance()
.nginxUserConfig(nginxUserConfig)
.init()
.start();
小结
整体而言 nginx.conf 的配置非常灵活。还有很多特性需要持续优化支持。
比如默认的全局配置,单独的 server 配置重载。