Spring的起源于J2EE密不可分,了解他们出现的历史,可以帮助我们更好的掌握Spring技术。
Java EE
什么是J2EE
❓问题1:什么是JAVA EE,他和JAVA语言本身,JAVA SE有什么关系呢? Java语言本身是一种编程语言,而Java SE、Java EE是Java平台的两个不同的版本,它们都基于Java语言。
- Java SE(Java Standard Edition):Java SE是Java平台的标准版,提供了Java语言的基本功能和核心API,包括面向对象编程、集合框架、输入输出、多线程等。
- Java EE(Java Enterprise Edition):Java EE是Java平台的企业版,建立在Java SE的基础之上,提供了一组扩展的API和工具,用于开发和部署大型、分布式、可扩展的企业级应用程序。Java EE包括了Java SE的全部功能,并提供了额外的企业级特性,例如Servlet、JSP、EJB、JPA、JMS等,以满足企业级应用程序开发的需求。
在实际开发中,Java EE应用程序通常运行在支持Java EE规范的应用服务器上,而Java SE则是Java EE的基础。 ❓问题2:使用JAVA SE,我只需要安装JDK,那我如何使用JAVA EE开发呢? 首先JAVA EE不是一个软件包,而是一组规范和API。我们可以导入J2EE相关库,在开发完成后,部署到支持 Java EE 标准的应用服务器上
java EE的起源
由于企业级应用需要处理的东西太多,包括网络、安全、数据库等等,1999年,SUN公司提出了一个想法:用**容器**
和**组件**
**的形式来提供服务,**容器负责共性的、底层的、复杂的内容,也为组件的运行提供环境,而组件负责具体的业务层面的内容。为了形成一个良好的JAVA开发生态,SUN公司还定义了一系列的规范,指定容器应该怎么做,组件应该怎么做。 容器是面向软件厂商,我们熟知的像tomcat就实现了J2EE容器规范,相应的还有jetty等等,而我们编写的程序,只要符合组件的规范,就可以跑在不同的容器上,这为程序的移植带来了极大的便利。
读一读这篇文章:IoC原理,介绍了为什么要使用IOC容器
最初的J2EE架构 J2EE出现的时候,正是WEB技术发展的时候,所以J2EE重点考虑如何为B/S架构的应用服务,基于MVC的思想,提出了EJB容器
+Web容器
,即业务逻辑层(M)+表示层(V)。
EJB容器与WEB容器有很多相同的地方,2002年10月份,Rod Johnson写了一本书《expert one to one J2EE Development without EJB》,基本思想是只使用Web容器而不使用EJB容器,并开发了一款在线订做应用,在这本书中,他使用了大量面向对象方法,实现了一个底层框架,在这个框架中第一次出现了依赖注入和AOP,这也是Spring Framework的起源(依赖注入和AOP与面向对象是息息相关的)。
java EE的发展简史
- **J2EE(Java 2 Platform, Enterprise Edition),**J2EE 最早发布于1999年。它提供了一套标准的规范、API 和技术,用于开发企业级应用程序。
- **Java EE(Java Enterprise Edition),**随着时间的推移,J2EE 迅速演化为
Java EE
,该名称首次出现在 Java EE 5 中。Java EE 引入了新的功能、简化了开发模型,并保持了向后兼容性。 - **Java EE 6,**该版本重点引入了 CDI(Contexts and Dependency Injection),并引入Servlet 3.0 规范,提供异步支持。
- **Jakarta EE 8,**从 Oracle 转向 Eclipse Foundation,持续改进符合当今云原生应用开发的需求。
Spring
很多教程讲解Spring的时候,都会直接介绍Spring的两大核心IOC和AOP。作为初学者,看到这些概念都会一头雾水,学了半天也只知道了一些概念,似懂非懂。了解Spring的发展和Spring的设计理念对于我们掌握Spring是非常有帮助的。
Spring
最早是由Rod Johnson在他的**《Expert One-on-One J2EE Development without EJB》**一书中提出的用来取代EJB的轻量级框架。随后这哥们又开始专心开发这个基础框架,并起名为**Spring Framework**
。
为什么需要IOC?
IOC是Spring中最重要的概念,IOC是一种设计原则,IoC 的起源可以追溯到面向对象技术的发展过程中。 我们先通过一个例子来看当没有IOC时,Java组件是如何协作的: 我们假定一个在线书店,通过BookService获取书籍:
public class BookService {
private HikariConfig config = new HikariConfig();
private DataSource dataSource = new HikariDataSource(config);
public Book getBook(long bookId) {
try (Connection conn = dataSource.getConnection()) {
...
return book;
}
}
}
为了从数据库查询书籍,BookService
持有一个DataSource
。为了实例化一个HikariDataSource
,又不得不实例化一个HikariConfig
。 现在,我们继续编写UserService获取用户:
public class UserService {
private HikariConfig config = new HikariConfig();
private DataSource dataSource = new HikariDataSource(config);
public User getUser(long userId) {
try (Connection conn = dataSource.getConnection()) {
...
return user;
}
}
}
因为UserService
也需要访问数据库,因此,我们不得不也实例化一个HikariDataSource
。 在处理用户购买的CartServlet中,我们需要实例化UserService和BookService:
public class CartServlet extends HttpServlet {
private BookService bookService = new BookService();
private UserService userService = new UserService();
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
long currentUserId = getFromCookie(req);
User currentUser = userService.getUser(currentUserId);
Book book = bookService.getBook(req.getParameter("bookId"));
cartService.addToCart(currentUser, book);
...
}
}
上述每个组件都采用了一种简单的通过new创建实例并持有的方式。仔细观察,会发现以下缺点:
- 实例化一个组件其实很难,例如,BookService和UserService要创建HikariDataSource,实际上需要读取配置,才能先实例化HikariConfig,再实例化HikariDataSource。
- 没有必要让BookService和UserService分别创建DataSource实例,完全可以共享同一个DataSource,但谁负责创建DataSource,谁负责获取其他组件已经创建的DataSource,不好处理。类似的,CartServlet和HistoryServlet也应当共享BookService实例和UserService实例,但也不好处理。
- **如何销毁组件?**很多组件需要销毁以便释放资源,例如DataSource,但如果该组件被多个组件共享,如何确保它的使用方都已经全部被销毁?
- 依赖关系复杂,代码编写难:随着更多的组件被引入,例如,书籍评论,需要共享的组件写起来会更困难,这些组件的依赖关系会越来越复杂。
- **难于测试:**测试某个组件,例如BookService,是复杂的,因为必须要在真实的数据库环境下执行。
💡从上面的例子可以看出,如果一个系统有大量的组件,其生命周期和相互之间的依赖关系如果由组件自身来维护,不但大大增加了系统的复杂度,而且会导致组件之间极为紧密的耦合,继而给测试和维护带来了极大的困难。
因此,核心问题是:
- 谁负责创建组件?
- 谁负责根据依赖关系组装组件?
- 销毁时,如何按依赖顺序正确销毁?
IOC的原理
传统的应用程序中,控制权在程序本身,程序的控制流程完全由开发者控制。在IoC模式下,控制权发生了反转,即从应用程序转移到了IoC容器,所有组件不再由应用程序自己创建和配置,而是由IoC容器负责,这样,应用程序只需要直接使用已经创建好并且配置好的组件。 因此,IoC又称为依赖注入(DI:Dependency Injection),它解决了一个最主要的问题:将组件的创建+配置与组件的使用相分离,并且,由IoC容器负责管理组件的生命周期。
Spring的发展
- Spring 1.0(2004年):
- 由 Rod Johnson 在 Interface21 公司发布。
- 提供了 IoC 容器、AOP(面向切面编程)、JDBC 抽象、事务管理等核心功能。
- Spring 2.0(2006年):
- 引入了新的功能,如注解驱动开发、更好的 AOP 支持和 AspectJ 集成。
- 增强了对多种持久化技术的支持,例如 Hibernate、JPA 等。
- Spring Web 模块也得到改进,提供了更好的 MVC 框架和 REST 支持。
- Spring 2.5(2007年):
- 引入了注解驱动的依赖注入。
- 提供了支持 JPA 的仓储库(Repository)模式。
- 引入了 SpEL(Spring Expression Language)用于 Spring 表达式的解析。
- Spring 3.0(2009年):
- 引入了基于 Java 5 的改进,如泛型依赖注入和注解。
- 提供了 REST 支持、Java EE 6 支持、更好的对注解的支持等。
- Spring 3.0 还提供了缓存抽象、任务执行器、TaskScheduler 等新特性。
- Spring 4.0(2014年):
- 引入了对 Java 8 的支持。
- 提供了对 Groovy 入口的支持。
- 改进了 REST 支持,引入了 WebSocket、心跳检测等新特性。
- Spring 5.0(2017年):
- 引入了对 Java 9 的支持。
- 提供了响应式编程模型,引入了 WebFlux、Reactor 支持。
- Spring 5.0 还改进了核心框架以及对 Java 8 的更好支持。
- Spring 5.1+:
- 后续版本继续改进和增强 Spring 框架,包括更好的 Kotlin 支持、对非阻塞 IO 的改进等。
- 通过不断更新和改进,Spring 框架在持续地适应并采纳最新的 Java 技术趋势和最佳实践。
Spring的生态
Spring 生态系统是指围绕 Spring 框架构建的一系列项目、工具和技术,用于支持和扩展 Spring 框架的功能,以满足不同应用场景和需求。Spring 生态系统包括以下主要组成部分:
- Spring Framework:Spring 框架是整个生态系统的核心,提供了关键功能,如依赖注入、面向切面编程、事务管理等。它是构建企业级 Java 应用程序的基础。
- Spring Boot:Spring Boot 是 Spring 提供的快速开发框架,简化了 Spring 应用程序的构建和部署过程。它通过自动配置和约定大于配置的原则,使开发者能够更快地搭建 Spring 应用,并集成了嵌入式 Web 服务器等功能。
- Spring Cloud:Spring Cloud 是用于构建分布式系统的微服务架构工具包。它提供了诸如服务发现、负载均衡、断路器、分布式配置等功能,使开发者能够轻松构建和管理基于云的分布式系统。
- Spring Data:Spring Data 为数据访问和集成提供了一致性的编程模型。通过 Spring Data,开发者可以更方便地操作各种数据存储,包括关系型数据库、NoSQL 数据库等。
- Spring Security:Spring Security 专注于为应用程序提供安全性。它支持认证、授权、攻击防护等功能,帮助开发者保护应用程序中的敏感数据和功能。
- Spring Batch:Spring Batch 是 Spring 生态系统中用于批处理任务的框架。它提供了处理大规模数据批量任务的能力,如数据导入、转换、处理等。
- Spring Integration:Spring Integration 是用于构建企业集成解决方案的框架,支持消息驱动架构和 EAI(企业应用集成)模式。
- Spring HATEOAS:Spring HATEOAS (Hypermedia as the Enigne of Application State)是 Spring 的超媒体 API,用于构建 RESTful 服务,并支持超媒体驱动的方法来管理应用程序状态。
- Spring WebFlux:Spring WebFlux 提供了响应式编程模型,支持异步和非堵塞的并发,适用于构建高性能、低延迟的 Web 应用程序。