软件框架(software framework),通常指的是为了实现某个业界标准或完成特定基本任务的软件组件规范,也指为了实现某个软件组件规范时,提供规范所要求之基础功能的软件产品。框架的功能类似于基础设施,与具体的软件应用无关,但是提供并实现最为基础的软件架构和体系。软件开发者通常依据特定的框架实现更为复杂的商业运用和业务逻辑。这样的软件应用可以在支持同一种框架的软件系统中运行。简而言之,框架就是制定一套规范或者规则(思想),程序员在该规范或者规则(思想)下工作。或者说使用别人搭好的舞台来做编剧和表演,也可以将框架理解为半成品软件。
Spring 是分层的 JavaSE/EE 应用 full-stack 轻量级开源框架,以 IOC(Inverse Of Control:反转控制) 和 AOP(Aspect Oriented Programming:面向切面编程) 为内核,提供了展现层 Spring MVC 和持久层 SpringJDBC 以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的 Java EE 企业应用开源框架。
☞ 挑衅 EJB
早期的 JavaEE 平台(J2EE)是推崇以 EJB 为核心的开发方式。这种方式存在以下几个弊端:
♞ 没有面向实际问题。J2EE 和 EJB 的很多问题都源自它们“以规范为驱动”的本质。标准委员会所指定的规范,并没有针对性地解决问题,反而在实际开发中引入很多复杂性。毕竟,成功的标准都是从实践中发展来的,而不是由哪个委员会创造出来的。
♞ 违反“帕累托法则”。“帕累托法则”也称“二八定律”,是指花较少的(10% ~ 20%)的成本解决大部分问题(80% ~ 90%),而架构的价值在于为常见的问题找到好的解决方案,而不是一心想要解决更复杂、也更为罕见的问题。EJB 的问题就在于,它违背了这个法则——为了满足少数情况下的特殊要求,它给大多数使用者强加上了不必要的复杂性。
♞ 引人重复代码。大多数 J2EE 代码生成工具所生成的代码都是用于实现 J2EE 经典架构的,这会导致引入很多重复代码、过渡工程等问题。
♞ 目标定位不清晰。早期的 EJB 2.1 规范中 EJB 的目标定位有 11 项之多。而这些目标,没有一项是致力于简化 JavaEE 开发的。
♞ 编成模型复杂。EJB 组成复杂,要使用 EJB 需要继承非常多的接口。而这些接口,在实际开发中并不是真正为了解决问题。
♞ 开发周期长。EJB 依赖于容器,所以 EJB 在编写业务逻辑时,是与容器耦合的。这必然就导致开发、测试、部署的难度增大。同时,也拉长了整个开发的周期。
♞ 移植困难。规范中定义的目标是“Write Once,Run Anywhere”,但实际上这基本是一句空话。
结果变成了一次编写,到处重写。特别是实体 Bean,基本上迁移了一个服务器,就相当于需要重新编写,相应的测试工作量也增加了。规范中对实体映射的定义太过于宽泛,导致每个厂商都有自己的 ORM 实现,引入特定厂商的部署描述符,又因为 J2EE 中除 Web 外,类加载的定义没有明确,导致产生了特定厂商的类加载机制和打包方式。同时,特定厂商的服务查找方式也是有差异的。
以上就是早期的 EJB 规范所存在的问题。Rod Johnson 正是不满意上述问题,从而推出了简化 JavaEE 开发的 Spring 框架。时代在进步,EJB 也在不断发展。新版的 EJB 3.2 已经有所改善了。
☞ Spring 化繁为简
EJB 最大的问题就是使用的复杂性,加上人为地对 EJB 技术的滥用、错用,让越来越多的 Java EE 开发者陷入“泥潭”。Spring 反其道而行之,化繁为简。主要表现为以下几个方面:
♞ 轻量级 IOC 容器。IOC 容器是用于管理所有 bean 的声明周期,是 Spring 的核心组件。在此基础之上,开发者可以自行选择要集成的组件,如消息传递、事务管理、数据持久化及 Web 组件等。
♞ 采用 AOP 编程方式。Spring 推崇使用 AOP 编程方式。AOP 面向切面编程的目标与 OOP 面向对象编程的目标并没有不同,都是为了减少重复和专注于业务。
♞ 大量使用注解。Spring 提供了大量的注解,支持声明式的注入方式,极大地简化了配置。
♞ 避免重复“造轮子”。Spring 集成了大量市面上成熟的开源组件,站在巨人的肩膀上,这样既增强了 Spring 的功能,又避免了重复“造轮子”。
☞ Spring 设计哲学
在了解一个框架时,不仅要知道它做了什么,更重要的是要知道它所遵循的设计原则。以下是 Spring 框架的指导原则。
♞ 在每个级别提供选择。Spring 允许开发人员尽可能地推迟设计决策。例如,可以通过配置切换持久化框架,而无须更改代码。许多其他基础架构问题及与第三方 API 的集成也是如此。
♞ 适应不同的观点。Spring 具有灵活性,并没有设定事情应该如何做。它以不同的角度支持广泛的应用需求。
♞ 保持强大的向后兼容性。Spring 的演变都会经过仔细的设计,以避免版本之间发生重大变化。
Spring 支持精心挑选的一系列 JDK 版本和第三方库,以方便维护依赖于 Spring 的应用程序和库。
♞ 精心设计 API。Spring 团队花费了大量的精力和时间来制作直观的 API,并且会长期支持多种版本。
♞ 为代码质量设定高标准。Spring 框架强调有意义的、最新的、准确的 Javadoc。这在开源项目中是非常少见的。很少有项目能够做到既可以声明简单的代码结构,又可以确保包之间没有循环依赖关系。
☞ Spring 面向未来
Spring 是开源的,它拥有一个庞大而活跃的社区,可根据各种实际用例提供持续的反馈。这使 Spring 在很长一段时间中能够成功的进化。经过十多年的发展,Spring 已经步入了第 5 个版本,它所支持的应用场景也越来越广泛。例如,在大型企业中,应用程序通常会存在很长时间,而且必须在 JDK 和应用程序服务器上运行,因为这些服务器的升级周期已经超出开发人员控制。而在另外的场景中,应用可能会被作为一个单一的 jar 包与服务器进行嵌入,并在云环境中运行,而另一些独立的应用程序(如批处理或集成工作负载)是完全不需要服务器的。
如今,随着时间的推移,JavaEE 在应用程序开发中的角色已经发生了变化。在 JavaEE 和 Spring 的早期阶段,创建的应用程序都需要部署到应用程序服务器中来运行。在 Spring Boot 的帮助下,应用程序以 DevOps 以云计算的方式来创建,Servlet 容器往往会被嵌入,并且变得微不足道。
从 Spring5 开始,WebFlux 应用程序甚至不直接使用 ServletAPI,这意味着应用可以在不是 Servlet 容器的服务器(如Netty)上运行。Spring 在不断创新和发展。除了 Spring 框架外,还有其他一些项目,如Spring Boot、Spring Security、Spring Data、Spring Cloud、Spring Batch 等,这些项目的成立旨在更加专注解决软件发展过程中不断产生的实际问题,以便带来更佳的开发体验。
核心容器(Core Container)由 spring-core、spring-beans、spring-context、spring-context-support 和 spring-expression(Spring Expression Language)模块组成。
♞ spring-core 和 spring-beans 模块提供框架的基础部分,包括 IOC 和 Dependency Injection 功能。BeanFactory 是一个复杂工厂模式的实现,无须编程就能实现单例,并允许开发人员将配置和特定的依赖从实际程序逻辑中解耦。
♞ Context(spring-context)模块建立在 Core 和 Beans 模块提供的功能基础之上,它是一种在框架类型下实现对象存储操作的手段,有一点像 JNDI 注册。Context 继承了 Beans 模块的特性,并且增加了对国际化的支持(如用在资源包中)、事件广播、资源加载和创建上下文(如一个 Servlet 容器)。Context 模块也支持如 EJB、JMX 和基础远程访问的 JavaEE 特性。ApplicationContext 接口是 Context 模块的主要表现形式。spring-context-support 模块提供了对常见第三方库的支持,以便集成到 Spring 应用上下文,如缓存(EhCache、JCache)、调度(CommonJ、Quartz)等。
♞ spring-expression 模块提供了一种强大的表达式语言,用来在运行时查询和操作对象图。它是作为 JSP2.1 规范所指定的统一表达式语言的一种扩展。这种语言支持对属性值、属性参数、方法调用、数组内容存储、收集器和索引、逻辑和算数的操作及命名变量,并且通过名称从 Spring 的控制反转容器中取回对象。表达式语言模块还支持列表投影、选择和通用列表聚合。
spring-aop 模块提供 AOP(面向切面编程)的实现,从而能够实现方法拦截器和切入点完全分离代码。使用源码级别元数据的功能,也可以在代码中加入行为信息,在某种程度上类似于 NET 属性。单独的 spring-aspects 模块提供了集成使用 AspectJ。spring-instrument 模块提供了类 instrumentation 的支持和在某些应用程序服务器使用类加载器实现。spring-instrument-tomcat 用于 Tomcat Instrumentation 代理。
自 Spring Framework 4 版本开始提供 spring-messaging 模块,主要包含从 Spring Integration 项目中抽象出来的,如 Message、MessageChannel、MessageHandler 及其他用来提供基于消息的基础服务。该模块还包括一组消息映射方法的注解,类似基于编程模型中的 Spring MVC 的注解。
数据访问/集成(Data Access/Integration)层由 JDBC、ORM、OXM、JMS 和 Transaction 模块组成。
♞ spring-jdbc 模块提供了一个 JDBC 抽象层,这样开发人员就能避免进行一些烦琐的 JDBC 编码和解析数据库供应商特定的错误代码。
♞ spring-tx 模块支持用于实现特殊接口和所有 POJO 类的编程及声明式事务管理。
♞ spring-orm 模块为流行的对象关系映射 API 提供集成层,包括 JPA 和 Hibernate。使用 spring-orm 模块,可以将这些 O/R 映射框架与 Spring 提供的所有其他功能结合使用,如前面提到的简单的声明式事务管理功能。
♞ spring-oxm 模块提供了一个支持 Object/XML 映射实现的抽象层,如 JAXB、Castor、JiBX 和 XStream。
♞ spring-jms 模块包含用于生成和使用消息的功能。从 Spring Framework 4.1 开始,它提供了与 spring-messaging 的集成。
Web 层由 spring-web、spring-webmvc、spring-websocket 和 spring-webflux 组成。
♞ spring-web 模块提供了基本的面向 Web 开发的集成功能,如文件上传及用于初始化 IOC 容器的 Servlet 监听和 Web 开发应用程序上下文。它也包含 HTTP 客户端及 Web 相关的 Spring 远程访问的支持。
♞ spring-webmvc 模块(也称 Web Servlet 模块)包含 Spring 的 MVC 功能和 REST 服务功能。
♞ spring-websocket 模块是基于 WebSocket 协议通信的程序开发。
♞ spring-webflux 模块是 Spring 5 新添加的支持响应式编程的 Web 开发框架。
spring-test 模块支持通过组合 JUnit 或 TestNG 来实现单元测试和集成测试等功能。它不仅提供了 Spring ApplicationContexts 的持续加载,并能缓存这些上下文,而且提供了可用于孤立测试代码的模拟对象(mock objects)。
通过 Maven 的依赖管理机制 我们只需要写 spring-context 的坐标即可,Maven 会自动将其依赖的 jar 导;但是不使用 Maven 则需要加入 spring-context、spring-beans、spring-core、spring-expression 这4个 jar 包。
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>${spring.version}version>
dependency>
/**
* Created with IntelliJ IDEA.
*
* @author Demo_Null
* @date 2020/8/11
* @description 持久层
*/
public class HelloWorldDao {
public String get() {
return "Hello World!";
}
}
/**
* Created with IntelliJ IDEA.
*
* @author Demo_Null
* @date 2020/8/11
* @description 服务层
*/
public class HelloWorldService {
public String show() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
HelloWorldDao helloWorldDao = (HelloWorldDao) applicationContext.getBean("helloWorldDao");
return helloWorldDao.get();
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="com.softrware.spring.dao.HelloWorldDao" id="helloWorldDao">bean>
<bean class="com.softrware.spring.service.HelloWorldService" id="helloWorldService">bean>
beans>
/**
* Created with IntelliJ IDEA.
*
* @author Demo_Null
* @date 2020/8/11
* @description 控制层
*/
public class HelloworldController {
@Test
public void show() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
HelloWorldService helloWorldService = (HelloWorldService) applicationContext.getBean("helloWorldService");
System.out.println(helloWorldService.show());
}
}
参考文献
[1] 柳伟卫.Spring 5 开发大全.北京.北京大学出版社.2018-10-1