如今做Java尤其是web几乎是避免不了和Spring打交道了,但是Spring是这样的大而全,新鲜名词不断产生,学起来给人一种凌乱的感觉,我就在这里总结一下,理顺头绪。
Spring
Spring 概述
Spring 是一个开源框架,是为了解决企业应用程序开发复杂性而创建的(替代更加重量级的企业级Java技术, 尤其是EJB),它完成了大量开发中的通用步骤,留给开发者的仅仅是与特定应用相关的部分,从而大大提高了企业应用的开发效率。
Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式如下图:
SpringFramework
组成 Spring 框架的每个模块都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:
-
Spring 核心容器:核心容器提供 Spring 框架的基本功能,管理着Spring应用中bean的创建、配置和管理。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用DI将应用程序的配置和依赖性规范与实际的应用程序代码分开。
-
Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。提供了一种框架式的对象访问方法,有些象JNDI注册器。Context封装包的特性得自于Beans封装包,并添加了对国际化(I18N)的支持(例如资源绑定),事件传播,资源装载的方式和Context的透明创建,比如说通过Servlet容器。Spring 上下文和Bean工厂都是 bean 容器 的实现。
-
Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。
-
Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
-
Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
-
Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。
-
Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。
Spring 核心特点:IOC和AOP
控制反转模式(IOC)也称作依赖性介入(DI)的基本概念是:不创建对象,但是描述创建它们的方式。在代码中不直接与对象和服务连接,但在配置文件中描述哪一个组件需要哪一项服务。容器 (在 Spring 框架中是 IOC 容器) 负责将这些联系在一起。在典型的 IOC 场景中,容器创建了所有对象,并设置必要的属性将它们连接在一起,决定什么时间调用方法。
Rod Johnson是第一个高度重视以配置文件来管理Java实例的协作关系的人,他给这种方式起了一个名字:控制反转(Inverse of Control,IoC)。后来Martine Fowler为这种方式起了另一个名称:依赖注入(Dependency Injection),因此不管是依赖注入,还是控制反转,其含义完全相同。
当某个Java对象(调用者)需要调用另一个Java对象(被依赖对象)的方法时,在传统模式下通常有两种做法
原始做法: 调用者主动创建被依赖对象,然后再调用被依赖对象的方法
简单工厂模式: 调用者先找到被依赖对象的工厂,然后主动通过工厂去获取被依赖对象,最后再调用被依赖对象的方法.
注意上面的主动二字,这必然会导致调用者与被依赖对象实现类的硬编码耦合,非常不利于项目升级的维护。使用Spring框架之后,调用者无需主动获取被依赖对象,调用者只要被动接受Spring容器为调用者的成员变量赋值即可,由此可见,使用Spring后,调用者获取被依赖对象的方式由原来的主动获取,变成了被动接受——所以Rod Johnson称之为控制反转。
另外从Spring容器的角度来看,Spring容器负责将被依赖对象赋值给调用者的成员变量——相当于为调用者注入它依赖的实例,因此Martine Fowler称之为依赖注入。
AOP(Aspect Orient Programming)也就是面向切面编程,作为面向对象编程的一种补充,已经成为一种比较成熟的编程方式。其实AOP问世的时间并不太长,AOP和OOP互为补充,面向切面编程将程序运行过程分解成各个切面。
AOP专门用于处理系统中分布于各个模块(不同方法)中的交叉关注点的问题,在JavaEE应用中,常常通过AOP来处理一些具有横切性质的系统级服务,如日志、事务管理、安全检查、缓存、对象池管理等,AOP已经成为一种非常常用的解决方案。
在典型的面向对象开发方式中,可能要将日志记录语句放在所有方法和 Java 类中才能实现日志功能。在 AOP 方式中,可以反过来将日志服务模块化,并以声明的方式将它们应用到需要日志的组件上,这样 Java 类就不需要知道日志服务的存在,也不需要考虑相关的代码。所以,用 Spring AOP 编写的应用程序代码是松散耦合的。
Spring 优点总结
-
低侵入式设计,代码的污染极低:很多框架通过强迫应用继承它们的类或实现它们的接口而导致应用与框架绑死,而Spring是通过spring特有的注解和通用的pojo结合。Spring的非侵入编程模型意味着这个类在Spring应用和非Spring应用中都可以发挥同样的作用。Spring的组件就是普通的Java Bean,这也使得单元测试可以不再依赖容器,编写更加容易。
-
使用模板消除样板式代码: 如Spring的JdbcTemplate使得执行数据库操作时避免传统的JDBC样板代码(创建一个数据库连接,然后再创建一个语句对象,最后你才能进行查询,关闭数据库连接、语句和结果集)成为了可能。
-
独立于各种应用服务器:基于Spring框架的应用,可以真正实现Write Once,Run Anywhere的承诺。
-
Spring的IoC容器降低了业务对象替换的复杂性,降低了了组件之间的耦合性:对象的依赖关系将由系统中负责协调各对象的第三方组件在创建对象的时候进行设定,所以对象无需自行创建或管理它们的依赖关系,依赖关系将被自动注入到需要它们的对象当中去。而且如果一个对象只通过接口而不是具体实现或初始化过程来表明依赖关系,那么这种依赖就能够在对象本身毫不知情的情况下,用不同的具体实现进行替换。
-
Spring的AOP支持允许将一些通用任务如安全、事务、日志等进行集中式管理: 将核心业务和系统服务分离,保持POJO的简单性和内聚性,从而使他们各自达到更好的复用。
-
Spring的ORM和DAO提供了与第三方持久层框架的良好整合,并简化了底层的数据库访问:
-
Spring的高度开放性,并不强制应用完全依赖于Spring,开发者可自由选用Spring框架的部分或全部:当Spring不能满足需求时, 完全可以考虑其他选择。事实上, Spring甚至提供了与其他第三方框架和类库的集成点, 这样你就不需要自己编写这样的代码了。比如以前常用的SSH框架,现在常用的SSM框架
Spring包含许多项目,下面挑一些最常用的出来总结一下。
Spring MVC
Spring MVC是Spring中的基础 Web 框架,基于模型-视图-控制器(Model-View-Controller,MVC)模式实现,它能够帮你构建像Spring框架那样灵活和松耦合的Web应用程序。
在该框架下,一次web请求大致可以分为如下图几个步骤,这些划分分离了职责,使得代码灵活、维护性更好。
为了使用该框架,我们首先要配置DispatchServlet,也就是前端控制器,然后启用Spring MVC,并编写控制器,视图,模型等等。
其中,DispatcherServlet是Spring MVC的核心,DispatcherServlet启动的时候,它会创建Spring应用上下文,并加载配置文件或配置类中所声明的bean或者自动扫描的bean,但是在Spring Web应用中,通常还会有另外一个应用上下文,这个应用上下文是由ContextLoaderListener创建的。DispatcherServlet加载包含Web组件的bean,如控制器、视图解析器以及处理器映射,而ContextLoaderListener要加载应用中的其他bean,通常是驱动应用后端的中间层和数据层组件。
Spring MVC是一个强大灵活的Web框架。借助于注解,Spring MVC提供了近似于POJO的开发模式,这使得开发处理请求的控制器变得非常简单,同时也易于测试。而且Spring MVC还支持多种视图解析器如JSP,Tiles,Thymeleaf,使得前端界面的功能更强大,编写更容易。
Spring Web Flow
Spring Web Flow是Spring MVC的一个扩展, 它为基于流程的会话式Web应用(购物车或者向导功能)提供了支持。简言之,它是一个流程框架,能够引导用户执行一系列向导步骤。
在Spring Web Flow中,流程是由三个主要元素定义的:状态、转移和流程数据。状态( State)是流程中事件发生的地点,在流程中通过转移的方式从一个状态到另一个状态,流程的当前状况称为流程数据。
状态分为:
-
行为( Action) 行为状态是流程逻辑发生的地方
-
决策( Decision) 决策状态将流程分成两个方向, 它会基于流程数据的评估结果确定流程方向
-
结束( End) 结束状态是流程的最后一站。一旦进入End状态, 流程就会终止
-
子流程( Subflow) 子流程状态会在当前正在运行的流程上下文中启动一个新的流程
-
视图( View) 视图状态会暂停流程并邀请用户参与流程
转移连接了流程中的状态。流程中除结束状态之外的每个状态,至少都需要一个转移,这样就能够知道一旦这个状态完成时流程要去向哪里。状态可以有多个转移,分别对应于当前状态结束时可以执行的不同的路径。
当流程从一个状态进行到另一个状态时,它会带走一些流程数据。有时候,这些数据只需要很短的时间(可能只要展现页面给用户)。有时候,这些数据会在整个流程中传递并在流程结束的时候使用。
Spring Web Flow 可以构建会话式应用程序的Web框架,这是好的,但是感觉其配置只能用xml这个设计不太合理,尤其是当bean很多或者流程节点很多时都不好维护。
Spring Security
安全对于许多应用都是一个非常关键的切面,因为安全性是超越应用程序功能的一个关注点,应用系统的绝大部分内容都不应该参与到与自己相关的安全性处理中。尽管我们可以直接在应用程序中编写安全性功能相关的代码,但更好的方式还是将安全性相关的关注点与应用程序本身的关注点进行分离,作为系统的一个切面。Spring Security就是通过AOP和Filter来为应用程序实现安全性的。
使用Servlet规范中的Filter保护Web请求并限制URL级别的访问。Spring Security还能够使用Spring AOP保护方法调用——借助于对象代理和使用通知,能够确保只有具备适当权限的用户才能访问安全保护的方法。
Spring Security非常灵活,能够基于各种数据存储来认证用户。它内置了多种常见的用户存储场景,如内存、关系型数据库以及LDAP。但我们也可以编写并插入自定义的用户存储实现。
当为浏览器渲染HTML内容时,你可能希望视图中能够反映安全限制和相关的信息。一个简单的样例就是渲染用户的基本信息( 比如显示“您已经以……身份登录”)。或者你想根据用户被授予了什么权限,有条件地渲染特定的视图元素。Spring Security本身提供了一个JSP标签库,而Thymeleaf通过特定的方言实现了与Spring Security的集成。借助于这些,可以很容易的实现对视图的保护。
Spring Data
Spring Data 是为了简化构建基于 Spring 框架应用的数据访问技术,包括关系数据库、NoSQL、Map-Reduce 框架、云数据服务等等,旨在提供一种通用、统一的编码模式(但是并不是代码完全一样),使得在Spring中使用任何数据库都变得非常容易。
Spring Data作为Spring Source的其中一个父项目,旨在统一和简化对各类型持久化存储,而不拘泥于是关系型数据库还是NoSQL数据存储。
目前的Spring Data 包含如下的模块(或者说子项目):
-
Spring Data Commons
-
Spring Data JPA
-
Spring Data KeyValue
-
Spring Data LDAP
-
Spring Data MongoDB
-
Spring Data Gemfire
-
Spring Data REST
-
Spring Data Redis
-
Spring Data for Apache Cassandra
-
Spring Data for Apache Solr
-
Spring Data Couchbase (community module)
-
Spring Data Elasticsearch (community module)
-
Spring Data Neo4j (community module)
无论是哪种持久化存储,数据访问对象(DAO,即Data Access Objects)通常都会提供对单一域对象的CRUD(创建、读取、更新、删除)操作、查询方法、排序和分页方法等。Spring Data则提供了基于这些层面的统一接口(CrudRepository,PagingAndSortingRepository)以及对持久化存储的实现。
你可能接触过某一种Spring模型对象——比如JdbcTemplate——来编写访问对象的实现。但是在基于Spring Data的数据访问对象,我们只需定义和编写一些查询方法的接口(基于不同的持续化存储, 定义有可能稍有不同),Spring Data会在运行时间生成正确的实现。
所有Spring Data的子项目都支持:
-
模板:处理资源分配和异常处理
-
对象、数据存储映射:如ORM
-
对数据访问对象的支持:帮助我们编写一些模板式语句如分页排序
然而一些Spring Data子项目,如Spring Data Redis和Spring Data Riak都只是提供模板,这是由于其相应的数据存储都只支持非结构化的数据,而不适用于对象的映射和查询。
Spring Boot
Spring诞生时是Java企业版(Java Enterprise Edition, JEE,也称J2EE)的轻量级代替品。无需开发重量级的Enterprise JavaBean(EJB),Spring为企业级Java开发提供了一种相对简单的方法。
虽然Spring的组件代码是轻量级的,但它的配置却是重量级的。一开始,Spring用XML配置,而且是很多的XML配置,即使后来有基于注解的改善,我们依然难逃大量配置的魔爪。而Spring Boot让这一切成为了过去,如果说Spring的目的是简化程序的开发,那么Spring Boot就是为了简化Spring本身的开发。
Spring Boot依赖于自动配置技术将Spring应用中样板式的配置移除掉,这样就能让我们免受于一大堆的配置之苦,更加专注于业务功能。Spring Boot同时还提供了多个Starter项目,拿来即可用,极大地简化了编程任务。
它提供了四个主要的特性,能够改变开发Spring应用程序的方式:
-
Spring Boot Starter:它将常用的依赖分组进行了整合,将其合并到一个依赖中,这样就可以一次性添加到项目的Maven或Gradle构建中,这里可以找到目前所有的starter项目。
-
自动配置:Spring Boot的自动配置特性利用了Spring 4对条件化配置的支持,合理地推测应用所需的bean并自动化配置它们,减少了你自己需要配置的数量。
-
命令行接口(Command-line interface,CLI):Spring Boot的CLI发挥了Groovy编程语言的优势,并结合自动配置进一步简化Spring应用的开发。
-
Actuator:它为Spring Boot应用添加了一定的管理特性。
Spring Cloud
在进入主题之前,首先来看看微服务,简单说来就是将原本单个独立的大系统拆分为分布式的多个小型的服务,这些小型服务各自独立运行,他们通过HTTP和RestFul API进行通信。
一个微服务一般完成某个特定的功能,比如下单管理、客户管理等等。每一个微服务都是微型六角形应用,都有自己的业务逻辑和适配器。一些微服务还会发布API给其它微服务和应用客户端使用。其它微服务完成一个Web UI,运行时,每一个实例可能是一个云VM或者是Docker容器。
微服务具有分布式系统的特性,如服务发现,负载均衡,故障转移,多版本,灰度升级,服务降级,分布式跟踪。
Spring Cloud是一套完整的分布式系统解决方案,它的子项目涵盖了所有实现分布式系统所需要的基础软件设施(包括配置管理、服务治理、智能路由、全局锁等等)。基于Spring Boot,Spring Boot做较少的配置,便可成为Spring Cloud中的一个微服务,使用Spring Cloud的开发者可以快速的启动服务或构建应用、同时能够快速和云平台资源进行对接,使得开发部署极其简单。
Spring Cloud专注于提供良好的开箱即用经验的典型用例和可扩展性机制覆盖:
-
分布式/版本化配置:Spring Cloud Config
-
服务注册和发现:Netflix Eureka 或者 Spring Cloud Eureka(对前者的二次封装)
-
路由:Spring Cloud Zuul 基于 Netflix Zuul
-
service - to - service调用:Spring Cloud Feign
-
负载均衡:Spring Cloud Ribbon 基于 Netflix Ribbon 实现
-
断路器:Spring Cloud Hystrix
-
分布式消息传递:Spring Cloud Bus
后记
总结了一大堆,感觉Spring Boot是趋势,毕竟效率是王道。然后就是Spring Data的各个项目,因为如今的数据源是越发的丰富。最后,近几年微服务的概念挺火的,所以Spring Cloud也要多多了解。