1 引导语
该专栏主要是讲解使用 SpringBoot 框架开发 Java 企业级 Web 应用的相关用法和原理,所以在进入 SpringBoot 框架的讲解之前,首先介绍一下 Java web 开发的相关原理,以便读者在之后能更好地理解基于 SpringBoot 开发 Java 企业级 Web 应用的相关用法和原理。
2 基于 Servlet 组件的 Java Web 应用开发
2.1 企业现状
Java 语言是目前最流行的企业级 Web 应用开发语言之一,在企业级 Web 应用开发当中,虽然 Java 也提供了JSP 技术来开发网页页面,但是目前的企业级 Web 应用一般都是采用前后端分离架构,所以 Java 语言主要用于开发服务端 Web Restful API 接口来供浏览器、安卓、IOS 等客户端调用。
2.2 Java 语言的 Web 通信实现: Servlet
在 Java Web 应用的运行过程当中,客户端与服务端之间是基于 HTTP 协议来进行通信的,Java 语言提供了 Servlet 组件来处理 HTTP 协议相关的底层细节,以及定义了处理 HTTP 请求的方法模板来供应用程序自定义业务处理逻辑,即接收客户端的 HTTP 请求,然后由应用程序自定义请求的业务处理逻辑,最后产生对应的 HTTP 响应返回给客户端。一个 Web 请求与响应的具体流程如图所示:
下面我们一起来学习下基于 Servlet 组件开发 Java Web 应用的核心实现流程:
- 自定义 Servlet 实现:在自定义 Servlet 的实现时,一般是通过继承 HttpServlet 并根据业务逻辑来重写其提供的对应HTTP 协议相关请求类型的处理方法,如 GET 请求,POST 请求等,分别为 doGet,doPost 方法等,不能根据业务特点来自定义其他名字的方法,HelloWorldServlet 的实现如下:
public class HelloWorldServlet extends HttpServlet { /** * HTTP GET请求处理 */ @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 自定义请求的业务处理逻辑 } /** * HTTP POST请求处理 */ @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 自定义请求的业务处理逻辑 }}
- 配置 URI 映射:在 Servlet 规范当中,需要在应用配置文件 web.xml 中为每个 Servlet 组件配置一个映射 URI,如下是在 web.xml 文件中配置 HelloWorldServlet 和 HelloWorldServlet 对应的 URI 映射,其中映射的 URI 为 “/servlet/helloworld”。所以如果应用存在多个 Servlet 实现,则需要在 web.xml 文件中配置每个 Servlet 和其对应的 URI 映射,
tips:由于每个 Servlet 都需要这样配置,所以如果存在大量 Servlet,则既会增加工作量,又非常容易配置错误,如路径 URI 拼写错误导致无法访问。
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- Servlet配置 --> <servlet> <!-- 该Servlet的名字,可以任意 --> <servlet-name>HelloWorldServlet</servlet-name> <!-- 该Servlet类的全限定名 --> <servlet-class>com.xyz.demo.HelloWorldServlet</servlet-class> </servlet> <!-- Servlet映射配置 --> <servlet-mapping> <!-- 需要和以上的Servlet的名字相同 --> <servlet-name>HelloWorldServlet</servlet-name> <!-- 浏览器访问该URL时,请求会被该Servlet处理 --> <url-pattern>/servlet/helloworld</url-pattern> </servlet-mapping></web-app>
- 打包部署:最后需要将这些 Servlet 组件编译打包到一个 war 包,然后将该 war 包部署到 Servlet 容器 Tomcat 中。后续的客户端请求都是发送给 Tomcat ,然后由 Tomcat 根据请求的 URL 来判断需要是哪个应用的请求和请求哪个 URI 路径, 最后转发给对应的 Servlet 组件处理。
知识拓展:Tomcat 是基于 Servlet 规范实现的 Servlet 容器,顾名思义,可以存放多个 Servlet 组件,故 Tomcat 中可以部署多个 Java Web 应用,每个应用由多个 Servlet 组件组成。
3 基于Servlet开发的痛点分析
基于 Servlet 开发 Java Web 应用是比较原始的开发方式,目前 Java 企业级应用一般很少直接使用这种方式,而是使用更高级的 Java Web 开发框架,如 Struts,SpringMVC 等,这些框架在内部封装了 Servlet 的相关细节,使得应用开发者只需要专注于业务开发即可。通过以上关于 Servlet 的介绍,我们可以总结出基于 Servlet 这种底层组件来开发 Java Web 应用存在以下痛点:
3.1 存在耦合
由以上 HelloWorldServlet 的定义可知,通过继承 HttpServlet 类,然后重写 HttpServlet 类根据 HTTP 请求类型定义的 doGet,doPost 等方法来实现业务逻辑的处理。这样就会导致应用业务逻辑与 Java 语言自身功能组件,即 Servlet 组件,存在耦合,不利于应用的拓展。
由于 Servlet 是以 HTTP 协议的请求类型维度来定义方法的,如果是业务逻辑复杂、存在大量 URL 的 Java Web 应用,则需要开发大量的 Servlet 类,不能做到在一个Servlet 类中定义多个不同 URL 的处理方法。
3.2 手动配置太多、可维护性差
需要在应用配置文件 web.xml 中配置每个 Servlet 和该 Servlet 的 URI 映射,所以如果应用存在大量的Servlet,则需要在 web.xml 中配置大量的 Servlet 和该 Servlet 的 URI 映射,使得 web.xml 文件内容太多,应用开发者维护难度大且容易配置出错,影响应用的可维护性;
3.3 部署困难
在部署层面,需要将 Java Web 应用打包为 war 包,然后部署到 Servlet 容器 Tomcat,故应用是运行在 Tomcat 进程的。同时由于可以在 Tomcat 部署多个 Java Web 应用,所以不能为每个应用都自定义相关的运行时参数,如配置 JVM 参数等来针对某个应用进行调优。
虽然可以通过在每个 Tomcat 进程只部署一个 Java Web 应用来实现,但是这种方式需要在服务器部署多个 Tomcat 进程或者每个服务器都需要部署一个 Tomcat 进程,额外增加了运维的工作量和服务器资源开销,特别是在微服务架构非常流行的今天,一个大型系统可能由成百上千个服务组成,如果基于这种方式部署,则对运维来说简直就是噩梦。
4 基于SpringMVC开发Java web应用
以上介绍了基于 Servlet 开发 Java Web 应用的相关用法和痛点,其中一个就是由于 Servlet 组件提供的相关方法太过底层,导致存在应用业务逻辑与 Java 语言自身功能组件的耦合,另外就是需要在 web.xml 中配置每个 Servlet和该 Servlet 对应的 URI 的映射,所以不利于应用的拓展和维护。所以为了解决这个问题,Spring 开发团队提供了 SpringMVC 框架。
SpringMVC 框架的核心设计主要包括三部分:
- 使用一个统一的 DispatchServlet 来接收应用的所有请求 ,只需要在应用配置文件 web.xml 中配置该DispatchServlet 和其 URI 映射即可,其中 DispatchServlet 是使用模糊匹配 “/*” 来拦截针对该应用的所有请求。
- 在 SpringMVC 框架内部定义了 MVC 模型的实现,即请求处理控制器 Controller,视图 View,数据模型 Model。其中业务请求处理方法和对应的 URI 的映射是在请求处理控制器 Controller 定义的,方法是从业务的角度,而不是 HTTP 请求类型的角度来定义的,故可以在一个 Controller 定义多个请求处理方法来处理不同的业务请求,在每个方法中使用 @RequestMapping 注解来定义对应的 URI 映射,且每个方法可以根据业务含义来命名,从而增加了应用代码的可读性和可维护性。
- 相对于基于 Servlet 开发 Java Web 需要定义大量 Servlet 类,SpringMVC 框架减少了应用中需要维护的类的数量,降低了开发难度,以及降低了业务与 Java 语言自身功能组件的耦合。
知识拓展:
不过由于 SpringMVC 框架是依赖于 Spring IOC 容器来对 Controller 等 Java bean 对象进行管理,所以需要在应用中维护 Spring 容器的配置文件applicationContext.xml。
SpringMVC 自身也存在配置文件 dispatcher-servlet.xml(名字可以自定义,具体可以查看 Spring 和 SpringMVC 的相关官方文档)。
最后还需要在应用配置文件 web.xml 中配置 SpringMVC 框架的请求分发器 DispatchServlet 和其 URI 映射。
以上列举了需要进行配置的三种配置文件,所以我们基于 SpringMVC 框架来开发 Java Web 应用也同样存在配置繁琐的问题。具体怎么样做才最简便,后面我们会讲到,一起来期待吧
^ ^。
5 基于SpringMVC的痛点剖析
5.1 维护性差
虽然 SpringMVC 框架解决了 Servlet 的方法太过底层,导致业务代码与 Java 自身功能组件代码存在耦合的问题,以及减少了应用中 Servlet 组件和在 web.xml 配置 URI 映射的数量。但是 SpringMVC 框架自身又引入了配置文件,如 Spring IOC 容器的配置文件 applicationContext.xml,SpringMVC 的配置文件 dispatcher-servlet.xml,或者基于注解和 Java 类的应用配置等。
由于可选的配置方式太多,导致不同应用开发人员可能会根据自身喜好选择其中一种配置方式,所以在项目的开发迭代过程中,项目会变得越来越难以维护,这样进一步增加了应用的开发和维护难度。
5.2 兼容性不好
除此之外,企业级 web 应用一般需要访问数据库,使用缓存等。所以需要依赖一系列其他第三方框架的功能 jar包,如基于 maven 进行 jar 包管理时,由于每个功能 jar 包都可能存在多个版本,故需要在 maven 包管理文件 pom.xml 中为每个功能 jar 包指定当前应用所使用的版本,并且可能会出现不同功能 jar 包的版本不兼容、类冲突等问题,从而导致程序启动失败。
所以应用开发人员需要额外测试和维护各个 jar 包版本的兼容关系,这也增加了 Java Web 应用的开发难度和复杂度。
5.3 部署困难
最后是基于 SpringMVC 进行 Java Web 应用开发也是需要将项目打包为 war 包,然后部署到 Tomcat,在Tomcat 进程运行该应用,所以没有从根本上解决 Java Web 应用对 Servlet 容器 Tomcat 的依赖,即还需要在服务器额外部署一个 Tomcat 进程来运行该应用,所以应用的相关运行参数,如 JVM 参数等,还是需要通过对Tomcat 进程来进行配置,而不能直接每个应用进行配置,以及也存在运维难度大等问题。
6 总结
我们今天讲了使用 Servlet 和 SpringMVC 这两种方式进行 Java Web 应用开发时,都存在需要在配置文件中进行大量配置的问题,并且随着应用越来越复杂,配置量也会越来越多,从而影响应用的拓展性,增加应用的开发和维护难度。
在部署的时候,应用都需要依赖于额外运行的 Tomcat 进程来运行,这种部署方式不能根据应用自身特点来指定应用的运行时参数,如 JVM 参数,还需要在服务器额外部署 Tomcat 进程,增加服务器的资源开销和运维工作量。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。