部署

对一个Web应用程序来说,除了Servlet、Filter这些逻辑组件,还需要JSP这样的视图文件,外加一堆静态资源文件,如CSS、JS等。

合理组织文件结构非常重要。我们以一个具体的Web应用程序为例:

  1. webapp
  2. ├── pom.xml
  3. └── src
  4. └── main
  5. ├── java
  6. └── com
  7. └── itranswarp
  8. └── learnjava
  9. ├── Main.java
  10. ├── filter
  11. └── EncodingFilter.java
  12. └── servlet
  13. ├── FileServlet.java
  14. └── HelloServlet.java
  15. ├── resources
  16. └── webapp
  17. ├── WEB-INF
  18. └── web.xml
  19. ├── favicon.ico
  20. └── static
  21. └── bootstrap.css

我们把所有的静态资源文件放入/static/目录,在开发阶段,有些Web服务器会自动为我们加一个专门负责处理静态文件的Servlet,但如果IndexServlet映射路径为/,会屏蔽掉处理静态文件的Servlet映射。因此,我们需要自己编写一个处理静态文件的FileServlet

  1. @WebServlet(urlPatterns = "/static/*")
  2. public class FileServlet extends HttpServlet {
  3. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  4. ServletContext ctx = req.getServletContext();
  5. // RequestURI包含ContextPath,需要去掉:
  6. String urlPath = req.getRequestURI().substring(ctx.getContextPath().length());
  7. // 获取真实文件路径:
  8. String filepath = ctx.getRealPath(urlPath);
  9. if (filepath == null) {
  10. // 无法获取到路径:
  11. resp.sendError(HttpServletResponse.SC_NOT_FOUND);
  12. return;
  13. }
  14. Path path = Paths.get(filepath);
  15. if (!path.toFile().isFile()) {
  16. // 文件不存在:
  17. resp.sendError(HttpServletResponse.SC_NOT_FOUND);
  18. return;
  19. }
  20. // 根据文件名猜测Content-Type:
  21. String mime = Files.probeContentType(path);
  22. if (mime == null) {
  23. mime = "application/octet-stream";
  24. }
  25. resp.setContentType(mime);
  26. // 读取文件并写入Response:
  27. OutputStream output = resp.getOutputStream();
  28. try (InputStream input = new BufferedInputStream(new FileInputStream(filepath))) {
  29. input.transferTo(output);
  30. }
  31. output.flush();
  32. }
  33. }

这样一来,在开发阶段,我们就可以方便地高效开发。

类似Tomcat这样的Web服务器,运行的Web应用程序通常都是业务系统,因此,这类服务器也被称为应用服务器。应用服务器并不擅长处理静态文件,也不适合直接暴露给用户。通常,我们在生产环境部署时,总是使用类似Nginx这样的服务器充当反向代理和静态服务器,只有动态请求才会放行给应用服务器,所以,部署架构如下:

  1. /static/* │
  2. ┌───────┐ ┌──────────> file
  3. │Browser├────┼─┤ │ ┌ ─ ─ ─ ─ ─ ─ ┐
  4. └───────┘ │/ proxy_pass
  5. │ └─────────────────────┼───>│ Web Server │
  6. Nginx
  7. └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ └ ─ ─ ─ ─ ─ ─ ┘

实现上述功能的Nginx配置文件如下:

  1. server {
  2. listen 80;
  3. server_name www.local.liaoxuefeng.com
  4. # 静态文件根目录:
  5. root /path/to/src/main/webapp;
  6. access_log /var/log/nginx/webapp_access_log;
  7. error_log /var/log/nginx/webapp_error_log;
  8. # 处理静态文件请求:
  9. location /static {
  10. }
  11. # 处理静态文件请求:
  12. location /favicon.ico {
  13. }
  14. # 不允许请求/WEB-INF:
  15. location /WEB-INF {
  16. return 404;
  17. }
  18. # 其他请求转发给Tomcat:
  19. location / {
  20. proxy_pass http://127.0.0.1:8080;
  21. proxy_set_header Host $host;
  22. proxy_set_header X-Real-IP $remote_addr;
  23. proxy_set_header X-Forwarded-Proto $scheme;
  24. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  25. }
  26. }

使用Nginx配合Tomcat服务器,可以充分发挥Nginx作为网关的优势,既可以高效处理静态文件,也可以把https、防火墙、限速、反爬虫等功能放到Nginx中,使得我们自己的WebApp能专注于业务逻辑。

练习

部署 - 图1下载练习:使用Nginx+Tomcat部署 (推荐使用IDE练习插件快速下载)

小结

部署Web应用程序时,要设计合理的目录结构,同时考虑开发模式需要便捷性,生产模式需要高性能。

读后有收获可以支付宝请作者喝咖啡,读后有疑问请加微信群讨论:

部署 - 图2 部署 - 图3