企业开发架构及技术的变更
写在前面
- 兴趣是学习最好的老师
- 知古鉴今
- 概述
- Java+Servlet
- Java+JSP
- JSP和PHP
- 前后端分离架构+Javascript+Restful+SpringMVC+Angular
- iframe实现企业应用集成
- 微应用架构
概述
在互联网飞速发展的过程中,企业开发所使用的技术及架构也在发生变化。过早的内容我们暂且不去描述,本文只从九十年代说起。那时是没有前端概念的,所有的事情都是后端在做,从业务逻辑到页面绘制,所使用的技术是java和servlet;后来页面内容逐渐丰富,引入了更加方便的jsp技术;再后来jsp的弊端逐渐显现,一种新的想法横空出世,引入前后端分离架构;随着前端后各自的不断深化,所能支撑的业务体量和复杂度不断攀升,也逐步引入了容器化、微服务、微应用架构...
Java+Servlet
Servlet是什么?
1997年,Sun 公司推出了 Servlet。Servlet 是 一种基于 Java 的动态网站开发技术。
严格来说,Servlet 只是一套 Java Web 开发的规范,或者说是一套 Java Web 开发的技术标准。只有规范并不能做任何事情,必须要有人去实现它。所谓实现 Servlet 规范,就是真正编写代码去实现 Servlet 规范提到的各种功能,包括类、方法、属性等。
Servlet 规范是开放的,除了 Sun 公司,其它公司也可以实现 Servlet 规范,目前常见的实现了 Servlet 规范的产品包括 Tomcat、Weblogic、Jetty、Jboss、WebSphere 等,它们都被称为“Servlet 容器”。Servlet 容器用来管理程序员编写的 Servlet 类。
![](https://img.haomeiwen.com/i3133116/1de6bbf1f810f45e.png)
如何使用Servlet?
public class HelloWorld extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Hello World</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Hello World!</h1>");
out.println("</body>");
out.println("</html>");
}
}
可以看到Servlet在展示页面的时候,输出HTML语句采用了老的CGI(Common Gateway Interface: Servlet之前渲染页面的方式,因servlet效率更高、可移植性更强、功能更强大而被替代)方式,是一句一句输出,所以,编写和修改HTML非常不方便,如果一个页面超级复杂,动不动几千行代码,那这个Servlet效率也就太低了。而且整个Servlet代码也会十分臃肿而且可读性非常差。
Applet
您可能还听说过 Applet,它和 Servlet 是相对的:
Java Servlet 是“服务器端小程序”,运行在服务器上,用来开发动态网站;
Java Applet 是“客户端小程序”,一般被嵌入到 HTML 页面,运行在支持 Java 的浏览器中。
Applet 和 Servlet 都是基于 Java 的一种技术,功能都非常强大,但是 Applet 开发步骤繁杂,而且只能在安装 Java 虚拟机(JVM)的计算机上运行,现在已经被 JavaScript 全面替代,几乎没有人再学习 Applet。
PHP
PHP 继承自一个老的工程,名叫 PHP/FI。PHP/FI 在 1995 年由 Rasmus Lerdorf 创建,最初只是一套简单的 Perl 脚本,用来跟踪访问他主页的人们的信息。它给这一套脚本取名为“Personal Home Page Tools”。随着更多功能需求的增加,Rasmus 写了一个更大的 C 语言的实现,它可以访问数据库,可以让用户开发简单的动态 Web 程序。Rasmus » 发布了 PHP/FI 的源代码,以便每个人都可以使用它,同时大家也可以修正它的 Bug 并且改进它的源代码。
后续
1997 年 11月 发布PHP/FI 2.0
1998 年 6 月 发布 PHP 3.0
2000 年 5月 发布 PHP 4.0
2004 年 7 月 发布 PHP 5.0
Java+JSP
首先要说明的一点是JSP基于Servlet,JSP的本质是将原本Servlet中关于页面绘制的内容单独抽离出来由专人负责,最终还是要将JSP编译成Servlet。
刚刚说到Servlet在开发页面时超级复杂,这里我们看JSP是如何解决这些问题的:
// Servlet
public class List_book extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//声明一个ArrayList.用来存放Book类中的数据
ArrayList<Book> list = new ArrayList<Book>();
for(int i=0;i<10;i++){
Book book = new Book();
book.setName(res.getString("name"+i));
book.setAuthor(res.getString("author"+i));
list.add(book);
}
//将list数据发送到.jap文件中
request.getRequestDispatcher("ListBook.jsp").forward(request, response);
}
}
// JSP
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%String path = request.getContextPath();%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="description" content="This is my page">
<script></script>
</head>
<body>
<% ArrayList list = (ArrayList) request.getAttribute("list"); %>
<h2 align = "center">图书列表</h2>
<table border = 1px align = "center">
<tr><th>图书名称</th><th>图书作者</th></tr>
<!-- 继续使用jsp语句 循环放入存放于list中的Book实体类中的数据 -->
<%
for(int i = 0;i<list.size();i++){
Book book =(Book)
list.get(i);%>
<tr><th><%=book.getName() %></th><th><%=book.getAuthor()%></th><tr>
}
%>
</table>
</body>
</html>
// EL表达式和JSTL标签库
<c:if test="${session.username==='admin'}">
Hello World!
</c:if>
<c:forEach items="${name}" var="name">
${name}<br />
</c:forEach>
首先页面更加直观了,然后利用MVC的思想将逻辑和UI分开,之后又引入了EL表达式和JSTL标签库,有效的解决了Servlet存在的问题,也使页面展示迈入一个新的台阶。JSP曾经风靡一时,直至现在,很多老的系统都有JSP的留存,需要进行维护。
JSP受到的威胁
虽然出现了EL和JSTL,但是还是有些程序员会忍不住直接在JSP中写java代码。后来就出现了Free Marker和Velocity等模板引擎,程序员完全无法里面写java代码了,其他都跟JSP差不多,通过标签来负责展示逻辑。另外模板引擎还可以脱离web容器使用,这是JSP无法做到的。模板引擎出现后,JSP损失了部分用户。
![](https://img.haomeiwen.com/i3133116/a8760bb716aeb9c5.png)
JSP存在的问题
- 动态资源和静态资源全部耦合在一起,服务器压力大,因为服务器会收到各种http请求,例如css的http请求,js的,图片的等等。一旦服务器出现状况,前后台一起玩完,用户体验极差。
- UI出好设计图后,前端工程师只负责将设计图切成html,需要由java工程师来将html套成jsp页面,出错率较高,修改问题时需要双方协同开发,效率低下。
- JSP必须要在支持Java的web服务器里运行(例如tomcat,jetty,resin等),无法使用nginx等(nginx单实例http并发高达5w,没有这个优势,性能提不上来)。
- 第一次请求JSP,必须要在web服务器中编译成servlet,第一次运行会较慢。
- 每次请求jsp都是访问servlet再用输出流输出的html页面,效率没有直接使用html高。
- jsp内有较多标签和表达式,前端工程师在修改页面时会遇到很多痛点。
- 如果jsp中的内容很多,页面响应会很慢,因为是同步加载。
- 需要前端工程师使用java的ide(例如eclipse),以及需要配置各种后端的开发环境,前端人员门槛较高。
JSP和PHP的区别
整体区别
- PHP是服务器脚本语言;JSP是服务器端编程技术。
- jsp使用Java语言,通过JDBC来访问数据库,访问数据库的接口比较统一;PHP对于不同的数据库采用不同的访问接口,访问数据库的接口不是很统一。
- Java采用面向对象,PHP采用面向过程。
php和jsp的语言比较
-
PHP是一种专为Web开发而设计的,解释执行的服务器脚本语言,它大量地借用C和Perl语言的语法,具有简单容易上手的特点,所以学过c语言的都可以很快的熟悉php的开发。
-
JSP是一种服务器端编程技术,有助于创建动态网页。它是以Java语言作为脚本语言,结合HTML语法的;熟悉JAVA语言和HTML语法的人可以很快上手。但java不光要需要学习语法,好用熟悉一些核心的类库,了解、掌握面向对象的相关知识。java要比PHP难学,因而JSP技术要比PHP难掌握。
php和jsp的数据库访问比较
- jsp使用Java语言,通过JDBC来访问数据库,通过不同的数据库厂商提供的数据库驱动方便地访问数据库。访问数据库的接口比较统一。
- PHP对于不同的数据库采用不同的数据库访问接口,所以数据库访问代码的通用性不强。例如:用Java开发的web应用从MySQL数据库转到Oracle数据库只需要做很少的修改。而PHP则需要做大量的修改工作。
php和jsp的性能比较
- JSP是基于Java编程语言,所以对API的支持非常庞大,在Web开发方面支持大量的第三方库。;而PHP对API的访问权限有限,支持的第三方库比较少。
- JSP支持对象缓存,而PHP不支持缓存。
- JSP是Java类的抽象,因此它可以被垃圾收集;而PHP不支持垃圾收集。
- JSP非常擅长维护用户会话,而PHP每次都会破坏用户的会话。
- JSP执行需要更多时间,因为它被转换为Servlet,编译和执行;而PHP执行所需的时间比JSP少,随着编码减少和快速开发和执行,即时反馈和更高的生产力。
php和jsp的系统设计架构比较
- 采用Java的web开发技术,需要使用的是面向对象的系统设计方法,而PHP还是采用面向过程的开发方法。所以用Java进行开发前期需要做大量的系统分析和设计的工作。
php和jsp的跨平台性比较
- Java和PHP都有很好的跨平台的特性。几乎都可以在不作任何修改的情况下运行在Linux或者Windows等不同的操作系统上。
php和jsp的开发成本比较
- PHP最经典的组合就是:PHP + MySQL + Apache。非常适合开发中小型的web应用,开发的速度比较快。而且所有的软件都是开源免费的,可以减少投入。
- JSP在学习周期和开发周期都比较长,且所需的软件不是全都免费的,开发成本比较高。
前后端分离架构+Javascript+Restful+SpringMVC+Angular
前后端分离
JSP存在的问题在淘宝等电商急速发展后越发明显。成千上万的页面管理,也让大家也意识到前端需要投入更多的精力了。这种前后端分离的思想就是后端工程师只关注于后端页面的开发,不再处理前端问题。前端工程师只关注于自己的页面开发。需要数据交互的时候,两者会有一份接口文档。
新的开发方式 SpringMVC+Angular
前后端分离思想很快流行起来,java从JSP转向了Restful结构,SpringMVC也开始流行起来。
前端页面上放弃了JSP,只使用简单的Html、CSS负责展示,动态的内容就引入了JavaScript。一般的做法就是使用ajax请求JSON,根据JSON内容动态渲染DOM。
为了让DOM渲染的更高效,前端工程师将MVC也搬到了前端,Angular框架就是如此,Angular使用js作为控制器,html作为视图,在js中异步去请求数据,然后html使用Angular标签来负责展示逻辑(就像JSTL、EL一样),把请求到的数据填充到html中,可以避免去直接操纵DOM。
从此,前后端各立门户,各建工程,分了前端工程和后端工程(前端也做工程化,也需要打包、测试、部署),只要约定好数据接口,大家在需求开发时可以并行开发,各司其职。展示有问题找前端,数据有问题找后端。
架构上的改变
以前的做法是所有动态、静态资源都打包成一个war包,部署到tomcat中,单机部署,单机提供服务,这对于以往一些流量不大的网站或者一些内部系统来讲,这种做法完全足够了。但是如今互联网性能要求越来越高,单点是不可能满足高性能,高并发,高可用的要求的。
现在的做法是静态资源全部部署到nginx中,动态资源放在tomcat中,也就是动静分离的思想。一个请求过来,先请求nginx的静态资源,浏览器加载静态资源后,通过nginx的反向代理请求后端服务器,这里还可以使用nginx的负载均衡,添加多台后端服务器
![](https://img.haomeiwen.com/i3133116/54482c594944dca9.png)
这样,html页面+json渲染 == 最终展示在用户面前的页面。
tomcat和nginx区别:
nginx是Http服务器,专为处理Http请求而诞生,处理Http请求能力强,适合用于处理静态资源(通过Http请求如实地返回内容,并且每个请求处理时间不会很长),底层采用单线程异步非阻塞方式,当读取静态资源发生IO时,可以先处理其他请求。据说nginx单机能抗5W并发。
tomcat是servlet/JSP容器,就是servlet/JSP运行的环境,tomcat把接收到的http请求交给servlet处理,然后servlet处理那些不讲逻辑的业务逻辑,适合处理动态资源。tomcat一般采用线程池的方式处理请求,当请求数量多,线程处理时间长,线程处理不过来,线程间会频繁切换,消耗大量cpu资源和内存。当请求超过一定的数量,会拒绝连接。因此JSP并不适合用于高并发的场景
iframe实现企业应用集成
企业应用集成的概念在JSP、PHP时代就已经比较广泛了。在开发大型项目时,为了提高性能,往往要分成多个模块进行开发,并且需要具有一定的扩展性,来应对未来的变化。
基于iframe的企业集成方案应运而生。
![](https://img.haomeiwen.com/i3133116/63b9cb57ba384eab.png)
当用户访问嵌入第三方服务的iframe页面时,本方服务向统一身份认证平台验证用户服务权限并得到第三方服务令牌,通过URL传送给第三方服务,第三方服务解析后向统一身份认证平台验证该用户权限令牌信息,若用户权限令牌信息正确则提供服务。
在此基础上,还可以通过浏览器提供的postMessage实现跨源通信。
这种集成方案被广泛应用与各个生产平台。
微应用架构
什么是微应用?
20世纪末,随着电商的兴起,业务需求越发旺盛,代码量骤增。网络公司,如 Netflix 和亚马逊,都面临着大规模软件开发的挑战。要将数百个贡献者对庞大的共享代码库进行修改所产生的摩擦降到最小,从而将代码库进行切割,使团队可以更快地行动,减少操作冲突。如今,移动开发团队也面临同样的挑战,另外,他们还面临着额外的挑战:应用程序作为单一的二进制文件交付,用户可以下载到自己的设备上运行。随着移动应用程序代码库的增长,编译成越来越大的二进制文件所需的时间也越来越长。为了应对这些问题,产生了微应用的概念。
微服务将后端分离出来的区域单独部署。与此类似,移动开发者可以将应用程序的不同核心部分——单一特性、共享业务逻辑和低级特性——转移到独立的模块库中。由此产生的模块彼此独立,并且独立于主要的应用程序代码库,团队可以自行处理它们。这种架构不同于其他强调模块化的方法,即微应用(Microapp)。
![](https://img.haomeiwen.com/i3133116/0030d50d404cd638.png)
因此,微应用的架构包括一个模块化设计,并辅之以专门的应用程序(称为微应用),供开发和测试使用,这就是为了提高开发者的速度。与 MVC (模型-视图-控制器)或 MVVM (模型-视图-控制器) 等明确定义的框架相比,它更像是一种抽象的框架,因为架构根据具体应用的特性而有所不同。然而,尽管没有一种放之四海而皆准的办法,但所有的成功实施都是一样的。
微应用的特点
- 技术栈无关:主框架不限制接入应用的技术栈,子应用具备完全自主权。
- 独立性强:独立开发、独立部署,子应用仓库独立。
- 状态隔离:运行时每个子应用之间状态隔离。
微应用的操作手册
-
注意系统间的界限:采用微应用架构需要时间,需要大量的学习和实验。在你最初的几次模块提取过程中,要注意你的系统组件之间的界限、一个组件的隔离和迁移要求,代码库应该如何组织,以及你的工具需要如何改进以支持应用程序的构建、测试和部署,因为应用程序已经变得完全模块化。
-
先抽离完全独立的模块:在应用程序中已被隔离或由多个特性共享的部分可以成为你第一个模块提取的理想选择。这几个模块只需对代码做一些简单的更改,让你的团队专注于提取过程本身并加以学习。例子包括基础组件,如 API 客户端;无处不在的用户界面元素,例如具有自定义风格的按钮;或没有上游依赖关系的低级特性集群,例如标准库扩展。
-
时常总结拆分模块的标准和方法:一旦你提取出三到五个模块,就把你所学到的转化为创建新模块的明确标准。这些标准应该规定一个模块的代码库应该如何组织,它应该如何集成到面向用户的应用程序中,以及它的 CI 设置。自动化应该使任何人都能生成构建新模块所需的“脚手架”。这种在学习、文档和工具方面的早期投资将为剩余的迁移工作奠定坚实的基础。
目前国内对微应用的应用
single-spa
single-spa是一个用于前端微服务化的JavaScript前端解决方案。single-spa的核心就是定义了一套协议。协议包含主应用的配置信息和子应用的生命周期,通过这套协议,主应用可以方便的知道在什么情况下激活哪个子应用。
配置信息
在single-spa中的配置信息也称为:Root Config,如下就是具体的配置项。需要配置子应用的名称,加载方式以及加载时机。
{
name: "subApp1", //子应用的名称
app: () =>//告诉主应用如何加载子应用的代码,
System.import("/a/b/subAPP/code"),
activeWhen: "/subApp1", //告诉主应用何时激活子应用
}
single-spa提供registerApplication将子应用的信息注册到主应用中。
singleSpa.registerApplication(
{
name: 'appName',
app: () => System.import('appName'),
activeWhen: '/appName',
}
)
过程如图
![](https://img.haomeiwen.com/i3133116/db011d4718a216b9.png)
qiankun
qiankun是基于single-spa提出的微前端框架, 提供了更加开箱即用的API(single-spa+sandbox+import-html-entry)。
Module Federation以及EMP
Module Federation是webpack5中的新特性,主要是用来解决多个应用之间代码共享的问题,可以更加优雅的实现跨应用的代码共享,使用这个方法也可以实现微前端。
公司内以及其他微前端框架
在搜索相关资料的时候,关注到公司内部和其他企业也有很多优秀的微前端的解决方法,比如司内的微前端oteam,无界和Hel微前端等产品,美团的基于React的中心路由基座式微前端和Bifrost框架,字节的lModern.js和lGarfish。微前端的生态逐渐繁荣,之后也会继续学习其相关的知识。
技术选型
当理解完理论开始实践时,第一关便是技术选型,现有的备选方案如上一章所述,这里提出一些具体的选型建议:
single-spa:是第一个微前端框架,当前流行的大量框架都是single-spa的上层封装,但是如果作为生产选型,single-spa提供的是较为基础的api,应用在实际项目中需要进行大量封装且入侵性强,使用起来不太方便。但是如果想学习相关技术或者封装一套更灵活的解决方法还是很值得使用的。
qiankun: 阿里开源的一套框架,基于single-spa的上层封装,社区活跃度较高,在国内的生态较好,中文文档齐全,有大量的先行者铺路,比较适合用于生产环境。
EMP: 基于module federation实现的一套可以跨应用共享资源的框架,除了具备微前端的能力外,还实现了跨应用状态共享、跨框架组件调用的能力,属于司外最年轻的微前端框架(暂时不适用于生产环境中),目前在github上是1.6kstar (qiankun是11.9k)。
微前端的进一步探索详见参考文章。
参考文章:
曾经风光无限的jsp技术,为什么现在很少有人用了呢?
从JSP的发展历程谈谈前后端分离
JSP的缺点和前后端分离的好处
了解一下iframe页面嵌入使用,轻松实现页面集成
JSP的前世今生~
PHP 的历史
Servlet到底是什么(非常透彻)
Servlet 简介
php和jsp之间有哪些区别
FreeMarker 快速入门
CGI与Servlet的区别和联系
了解新兴架构模式:微应用架构
微前端究竟是什么?微前端核心技术揭秘!