最近在学习企业开发领域很流行的SSH框架(Struts、Hibernate、Spring),由于之前有做过原生的Servlet+JSP的项目,所以在学习过程中我会跟原生开发模式进行对比,在这里我把自己的一些理解做下小结。
1、Servlet+JSP原生开发
先简要说一下Java Web原生开发模式,Java Web开发通常是使用Tomcat之类的容器,Tomcat容器实现了一套也可以称为框架的东西,就是Servlet。Tomcat运行于Apache之类的Web服务器上,Apache服务器负责处理用户请求的HTTP协议本身的部分。当用户请求的HTTP协议部分被Apache服务器处理之后,内容部分就要由Tomcat来处理了。Tomcat归纳了Web请求的共同特性,封装了一个叫Servlet的东西,开发者基于Servlet,就只需要编写处理Web请求的具体逻辑部分了,至于HTTP请求字段的解析,响应字段的封装都交给Servlet了。另外对于Web页面的拼接生成,是使用JSP脚本,Tomcat容器内置有解析器,可以把JSP文件解析成Servlet来执行。JSP除了包含HTML/CSS/JS内容以外,有一些JSP的标签语法,用于Servlet向JSP传递一些对象,这样就可以把Servlet处理的结果动态的在JSP页面中显示出来,从而实现动态页面的效果。
2、Struts框架
我们来看下原生开发的的一些不足,这样才能较好的理解为什么会有Struts框架。其实从功能实现角度来说,一般的Web开发用Servlet基本是可以满足的,但是当项目规模比较大的时候,就会显得比较凌乱,因为会定义大量的Servlet,各个Servlet的处理流程会有一些相同的部分,每个Servlet都需要去重复实现。针对这个问题,SSH框架中的Struts基于软件分层的思想,把Web处理流程中各个部分独立开来,并且把Servlet相同的处理逻辑放到框架来实现,从而把开发人员从重复中释放出来,聚焦于具体业务功能实现。Struts采用称为MVC的设计模式,把Web应用分为数据库访问(M)、业务逻辑(C)、JSP页面(C)三个部分。能够通过XML配置文件的方式,把不同的Action访问引导到对应的Action类进行处理,并且根据Action类处理的结果,在XML中配置不同的结果调用不同的JSP页面资源。
Struts还把Web开发中一些常用通用的工作整合进了框架内:
1)国际化资源文件,如果用原生开发模式,JSP中的字符串多语言需要自己实现,在各个JSP文件中引入各自语言的JSP字符串定义文件,如果使用Struts就可以由框架来实现,并通过XML配置。
2)JSP标签,针对原生JSP的不足,Struts定义了一些标签,增强了JSP的表达能力。
3)输入类型转换,这个工作如果是原生开发通常也是由开发人员自己实现的,使用Struts就可以由框架来帮助完成请求参数到内建对象成员之间相互转换。
4)输入校验,这个工作如果是原生开发通常也是由开发人员自己实现的,使用Struts就可以通过XML定义的方式,由框架来帮助实现。
5)拦截器,由于如果使用Struts,那么Struts就接管了处理Web请求的整个过程,用户没法自由的在处理过程中插入一些必要的逻辑代码。所以框架提供了拦截器这样的机制,能够让开发者在Web请求处理过程中插入一些需要的处理逻辑,通过在XML定义拦截器的方式来提供。
从上面分析可以看出,相比于原生开发,从功能角度Struts并没有增强多少,Struts主要的工作就是帮助我们把Web应用进行比较好的分层,同时把一些重复的工作集成到框架来完成,这就是框架的作用。
3、Hibernate框架
不论采用原生开发模式还是Struts框架,我们都需要自己实现Web应用的具体逻辑部分,这其中包括对数据库的访问。对于Web应用来说,数据库访问所占的比重是比较多的,特别是近年来流行的比如ArgularJS之类的前端框架,都有把原本在后端实现的业务逻辑放到前端来实现,如果这样,后端的工作就主要只剩下数据库访问和安全相关功能了。如果我们采用原生开发模式,我们需要自己实现对数据库的CRUD访问,通常要编写SQL语句直接访问数据库,然后解析SQL访问的结果,并封装到Java对象中提供给上层使用。如果后期切换不同数据库,我们就需要重新编写SQL处理代码并适配。
Hibernate框架帮我们封装了对数据库的访问,为我们提供了另外一种选择。它通过XML配置的方式,完成数据库连接,把数据库表映射到Java对象,并且能够把表之间的关联关系也通过XML配置映射到Java对象中,这样开发人员访问数据库时就只需要面对Java对象进行操作,而不用自己去实现原生开发的那些工作了,这样就能从具体的数据库操作中解放出来,后期如果切换数据库通常只用修改XML配置就可以了。这种方式的不足就是增加的了XML的配置。
4、Spring框架
Spring框架实现主要包含两个核心机制,一个是IOC(依赖注入),另一个是AOP(切面注入),我现在分别来分析。
IOC解决的是对象之间的依赖问题,Java是面向对象语言,Web应用会定义大量的对象,对象之间也有相互关联。在通常的开发模式下,我们需要编程来创建各种Java对象,并且把它们互相关联起来,这样做的缺点是对象之间的耦合比较多,后续维护变更时会需要修改代码。IOC提供了另外一种做法,就是对象和对象之间关系通过XML方式定义,然后Spring框架通过Java反射机制帮我们创建这些对象,并按照定义把对象相互关联起来,之后就可以提供给业务逻辑使用了。有人会想,自己创建对象和框架创建对象哪种好,这可能各人有各人的看法,对于大型工程来说,Spring关联对象创建和关联可能更清晰,但由此带来的代价就是XML配置的膨胀。所以实际中通常对于大的组件级的对象可以采用IOC注入,对于细小的对象还是自己创建管理,这样可以取得两者之间的平衡。
AOP是一个重要思想在Spring框架中的具体实现,就是面向切面编程。这个思想简单的说,就是对已有程序的某个接口插入一些另外处理逻辑,这是怎样做到的呢?这依赖于IOC机制,由于使用IOC,对象由框架创建,当AOP在XML中定义了切入点和切面函数后,再定义这些切入点指向的IOC对象,之后框架在创建这些IOC对象时,就会通过Java的动态代理机制,对这些IOC对象生成相应的动态代理,并在定义的切入点把切面函数集成进去。当用户程序调用这些代理对象切入点的函数时,也会自动调用切面函数,这样就实现了把切面函数的注入。通过这种机制就能够把独立切面函数随意注入需要切入的IOC对象中去,在实际中的一个典型应用就是为对象增加事务机制,能够把事务处理独立的注入需要事务的对象里,这样事务处理就不用与需要事务的对象紧密耦合。除了事务,在Web系统中一些具有横切性质的服务通常也会使用AOP来实现,比如安全检查、缓存、对象池管理等。
5、总结
从上面的分析可以看出来,Servlet帮我们封装了Web请求和响应的通用处理逻辑,而SSH又在Servlet的基础上又帮我们封装了一些Web应用系统的通用处理逻辑,软件就是这样一层一层的叠加而成,遇到通用的地方就进行抽象封装。当然封装的代价是增加了许多XML配置,这也是许多人诟病SSH配置繁复的原因,在实际项目怎样取舍我想每个人心中都有一杆秤。
(完)