为什么我们需要Spring Framework ?
Posted 有且仅有
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么我们需要Spring Framework ?相关的知识,希望对你有一定的参考价值。
一、为什么我们需要Spring Framework ?
1. 从J2EE说起
- 1998 年Sun 公司发表JDK 1.2 时,分别发表了标准版-J2SE、企业版-J2EE、微型版-J2ME。J2EE 诞生。
- 2005 年Java One 大会上Sun 公布了JDK 1.6,J2XX 全部改名为JavaXX,J2EE 改名为JavaEE。
- 2018 年3月,Eclipse 基金会将JavaEE 更名为Jakarta EE。(2017 年Oracle 将JavaEE 移交给开源组织Eclipse 基金会,但不允许其继续使用Java一词)
Java EE 是一个技术体系的统称,它包含了:
- EJB - Enterprise Java Beans.
- JNDI - Java Naming and Directory Interface.
- JDBC - Java Database Connectivity.
- JMS - Java Message Service.
- Servlet - Java Servlet API.
- JSP - Java Server Pages.
- …
2. EJB - Enterprise Java Bean
EJB 是J2EE 规范的核心内容,也与我们要说的Spring 的诞生密切相关。EJB 2.0 在2001 年8月发布,EJB 的工作方式如下:
EJB 提供了一种组件模式,使得开发人员可以仅关注系统业务方面的开发,而忽略中间件需求,比如:组件、远程调用、事务管理、持久化等等。在需要的时候开发人员可以随意将需求的中间件服务添加到系统中。至少从表面上看,这一切非常完美和有前途。但是你知道的,事实上并非如此。
EJB 存在的问题?
业务类需要与EJB 框架紧耦合,必须编写多个接口才能创建业务组件
EJB 2.X 要求组件接口
interface
和业务逻辑实现类class
都必须从EJB 框架包中扩展接口,这使得开发人员编写的代码和EJB 框架的接口类之间产生了紧耦合。顺带的,我们还必须实现几个不必要的回调方法,例如ejbCreate(), ejbPassivate(), ejbActivate(), ...
。为了开发一个EJB 组件,开发人员至少需要写三个不同的类,分别针对主程序、远程接口和业务对象:
/** * 远程接口,使客户端可以远程调用EJB 组件的业务功能 */ public interface PetService extends EJBObject void saveOwner(Owner owner) throws RemoteException; /** * 主接口,使客户端可以获取EJB 组件的句柄 */ public interface PetServiceHome extends EJBHome PetService create() throws RemoteException, CreateException; /** * 无状态会话Bean */ public class PetServiceBean implements SessionBean private SessionContext sessionContext; // 以下为EJB 要求实现的方法 public void ejbCreate() public void ejbRemote() public void ejbActivate() public void ejbPassivate() public void setSessionContext(SessionContext sessionContext) this.sessionContext = sessionContext; /** * 业务方法 */ public void saveOwner() throws java.rmi.RemoteException // 业务代码
RMI 带来不必要的性能开销。一个J2EE 服务器中同时有Servlet 容器和EJB 容器,不可接受的是Servlet 容器必须通过RMI 来调用EJB。为了避免RMI 这个问题,EJB 最终又引入了本地接口(还记得1里说的“至少”吗?)。
部署时需要些冗长的XML部署描述符,这很不直观且易出错。
难以在容器之外进行单元测试:JNDI 的依赖查找,使得对组件进行单元测试很困难,因为对JDNI 上下文的依赖。
面向过程:EJB 编程模型将开发人员引向了面向过程程序设计风格,数据和行为被分离而不是以内聚的形式在一起。在这里不辩论编程风格,只不过我们使用的Java 是面向对象的编程语言,因此我们肯定想充分利用Java 的优点,不是吗?
3. POJO 编程模型
正是由于上述的种种问题,EJB 2.X 逐渐被人们厌恶。而与此同时,与EJB 编程模型完全不同的POJO 编程模型发展起来了。
POJO - Plain Old Java Object 一词被发明出来,是为了描述那些:不需要实现任何特定接口或者扩展自某一特定框架类的最简单的类。它也使得我们可以专注于从面向对象的角度来编写代码。
我们的主角来了:
基于POJO 编程模型产生了很多框架,在这其中Spring Framework 是最成功的一个框架,它已经成为事实上的开发JavaEE 应用程序的标准框架。
需要知道的一点是:在EJB 3.X 中,上述问题大部分都已经得到了解决,不过在此之前Spring Framework 已经发展壮大了。另外,在EJB 所有改进中最重要的一点就是EJB 规范引入了POJO 编程模型。显而易见,这在很大程度上要归功于Spring Framework 产生的影响。另外,当前的Spring Framework 已经兼容了很多EJB 规范。例如:@Resource, @PostConstruct, @PreDestroy
。
4. 总结:我们为什么需要Spring Framework ?
在EJB 2.X 这个历史时间阶段上,由于其本身的设计问题,导致使用EJB 模型来开发会提高复杂度,这其中最重要的问题是:业务类需要与EJB 框架紧耦合。
而在这个时间节点上诞生的Spring Framework ,给我们提供了更简单易用的一个选择。业务代码纯粹,我们业务代码不必依赖框架中服务的API,且这些服务是可插拔的。(业务代码纯粹、服务可插拔)
二、Spring Framework 为我们带来了什么?
2002 年Rod Johnson 在 expert one-on-one J2EE Design and Development 一书中发表了Spring Framework 的第一个版本。
后来他又陆续发布了 expert one-on-one J2EE Development without EJB
以及Professional Java Development with the Spring Framework
Spring Framework 为我们带来了一个轻量级容器,使我们可以在没有被“侵入”的情况下写业务代码。
1. 轻量级容器
Java EE 的容器
在Java EE 中有一个“容器”的概念,它是指这样一个环境:在该环境中所有组件都被创建和装配,并且提供了所需要要的中间件服务。
Java EE 提供了多个容器:
Servlet 容器负责创建和管理Web 层组件
比如Servlet、JSP、Filter。
EJB 容器专注于业务层
管理EJB 组件。
轻量级容器
任何容器都应该向它所管理的组件提供一些基本服务。根据expert one-on-one J2EE Development without EJB 一书,可以列出如下所述的一些预期服务:
- 生命周期管理
- 依赖解析
- 组件查找
- 应用程序配置
如果能够再进一步提供一些中间件服务,那就更好了:
- 事务管理
- 线程管理
- 对象和资源池
- 对组件的远程访问
- 容器的扩展和定制
一个轻量级容器(lightweight container)包含上述所有功能,但并不需要依赖那些API 来编写代码。也就是说轻量级容器没有侵入特性,在企业级Java 世界中,Spring Framework 就是最著名的轻量级容器。
2. 控制反转
容器及其管理的组件所提供的最重要的好处是:可插拔的体系结构。组件需要实现一些接口,并且可以通过类似的接口访问其他组件所提供的服务。组件不需要知道这些服务的具体实现类,因此实现是很容易替换的。容器的工作是:创建这些组件以及所依赖的服务,并将这些组件装配在一起。
控制反转:在组件类中,组件不需要实例化其所依赖的其它组件,而是在运行时由容器将被依赖的组件注入到这个组件中。这种模式被称为控制反转(Inversion of Controll),简称IoC,即对依赖的控制权由组件自己反转到了容器。
IoC 是任何容器都要提供的基本功能,它主要有两种实现方式:依赖查找(dependency lookup)和依赖注入(dependency injection):
依赖查找
容器向其管理的组件提供了回调方法,组件通过回调方法来显式地获取它所需要的依赖。通常使用一个“查找上下文”来访问依赖组件。
依赖注入
组件必须提供合适的构造函数或者Setter 方法,以便容器可以为组件注入其依赖的其他组件。
在最初的J2EE 中,所使用的主要方法是依赖查找,上面提到的“查找上下文”在这里就是JNDI。随着Spring Framework 等很多轻量级容器的出现,依赖注入变得流行起来。如今,当开发人员再提及IoC 时,通常会被理解为依赖注入。
3. 依赖注入
依赖注入的基本原则是:应用程序对象不应该负责查找它们所依赖的资源,而是由IoC 容器处理对象的创建和依赖注入。
一个好的容器应该同时支持构造函数注入和Setter 注入。
Setter 注入
当一个对象被实例化后其Setter 方法就会被马上调用。
优点
在组件被配置后,可以在运行时重新配置,这是因为Setter 方法本身是JavaBean 规范的内容,所以外部世界也可以在之后修改其依赖值。
缺点
有可能并不是所有的依赖项都可以在使用前被注入,从而使组件处于一种部分配置状态(Setter 循环依赖)。由于Setter 的顺序无法在组件中得到约定,可能会产生状态不一致的情况。
构造函数注入
优点
每一个被管理的组件都处于一致状态(循环依赖会直接报错),且在创建后可以马上使用。
缺点
无法在组件创建完毕后再对组件进行重新配置。
实际使用中,一般我们会混合使用这两种注入方式。
以上,我们知道了“为何使用Spring Framework?”,以及Spring Framework 为我们带来了什么。
以上是关于为什么我们需要Spring Framework ?的主要内容,如果未能解决你的问题,请参考以下文章
java maven项目 引用了spring-framework-bom 为啥下面的jar包还需要写版本号?
spring (由Rod Johnson创建的一个开源框架)
为啥 UIView 不需要 QuartzCore.framework 工作?