Java笔记 ·

Spring基础小结

Spring是什么

Spring是一个开源的轻量级Java SE(Java 标准版本)/Java EE(Java 企业版本)开发应用框架,其目的是用于简化企业级应用程序开发。

Spring能帮我们做什么

a.Spring能帮我们根据配置文件创建及组装对象之间的依赖关系。

b.Spring 面向切面编程能帮助我们无耦合的实现日志记录,性能统计,安全控制。

c.Spring能非常简单的帮我们管理数据库事务。

d. Spring还提供了与第三方数据访问框架(如Hibernate、JPA)无缝集成,而且自己也提供了一套JDBC访问模板,来方便数据库访问。

e.Spring还提供与第三方Web(如Struts、JSF)框架无缝集成,而且自己也提供了一套Spring MVC框架,来方便web层搭建。

f.Spring能方便的与Java EE(如Java Mail、任务调度)整合,与更多技术整合(比如缓存框架)。

为什么需要Spring及Spring的优点

  • 非常轻量级的容器:以集中的、自动化的方式进行应用程序对象创建和装配,负责对象创建和装配,管理对象生命周期,能组合成复杂的应用程序。Spring容器是非侵入式的(不需要依赖任何Spring特定类),而且完全采用POJOs进行开发,使应用程序更容易测试、更容易管理。而且核心JAR包非常小,Spring3.0.5不到1M,而且不需要依赖任何应用服务器,可以部署在任何环境(Java SE或Java EE)。
  • AOP:AOP是Aspect Oriented Programming的缩写,意思是面向切面编程,提供从另一个角度来考虑程序结构以完善面向对象编程(相对于OOP),即可以通过在编译期间、装载期间或运行期间实现在不修改源代码的情况下给程序动态添加功能的一种技术。通俗点说就是把可重用的功能提取出来,然后将这些通用功能在合适的时候织入到应用程序中;比如安全,日记记录,这些都是通用的功能,我们可以把它们提取出来,然后在程序执行的合适地方织入这些代码并执行它们,从而完成需要的功能并复用了这些功能。
  • 简单的数据库事务管理:在使用数据库的应用程序当中,自己管理数据库事务是一项很让人头疼的事,而且很容易出现错误,Spring支持可插入的事务管理支持,而且无需JEE环境支持,通过Spring管理事务可以把我们从事务管理中解放出来来专注业务逻辑。
  • JDBC抽象及ORM框架支持:Spring使JDBC更加容易使用;提供DAO(数据访问对象)支持,非常方便集成第三方ORM框架,比如Hibernate等;并且完全支持Spring事务和使用Spring提供的一致的异常体系。
  • 灵活的Web层支持:Spring本身提供一套非常强大的MVC框架,而且可以非常容易的与第三方MVC框架集成,比如Struts等。
  • 简化各种技术集成:提供对Java Mail、任务调度、JMX、JMS、JNDI、EJB、动态语言、远程访问、Web Service等的集成。
    Spring能帮助我们简化应用程序开发,帮助我们创建和组装对象,为我们管理事务,简单的MVC框架,可以把Spring看作是一个超级粘合平台,能把很多技术整合在一起,形成一个整体,使系统结构更优良、性能更出众,从而加速我们程序开发,有如上优点,我们没有理由不考虑使用它。

Spring架构图

Spring架构图
Spring架构图

1、核心容器

包括Core、Beans、Context、EL模块。

spring-core 和 spring-beans 模块提供了框架中最基本的部分,包括控制反转和依赖注入。

  • Core模块spring-core ,封装了框架依赖的最底层部分,包括资源访问、类型转换及一些常用工具类。
  • Beans模块spring-beans,提供了框架的基础部分,包括反转控制和依赖注入。其中Bean Factory是容器核心,本质是“工厂设计模式”的实现 ,而且无需编程实现“单例设计模式”,单例完全由容器控制,而且提倡面向接口编程,而非面向实现编程;所有应用程序对象及对象间关系由框架管理,从而真正把你从程序逻辑中把维护对象之间的依赖关系提取出来,所有这些依赖关系都由BeanFactory来维护。
  • Context模块:spring-context,以Core和Beans为基础,集成Beans模块功能并添加资源绑定、数据验证、国际化、Java EE支持、容器生命周期、事件传播等;核心接口是ApplicationContext。
    spring-context-support 支持将常见的第三方库集成到Spring 应用上下文,如缓存(EhCache,Guava,JCache),邮件(JavaMail),调度(CommonJ,Quartz)和模板引擎(FreeMarker,JasperReports,Velocity)。
  • EL模块:提供强大的表达式语言支持,支持访问和修改属性值,方法调用,支持访问及修改数组、容器和索引器,命名变量,支持算数和逻辑运算,支持从Spring 容器获取Bean,它也支持列表投影、选择和一般的列表聚合等。

2、AOP 及 Instrumentation

  • spring-aop 模块提供 AOP Alliance-compliant(联盟兼容)的面向切面编程实现,允许你自定义,比如,方法拦截器和切入点完全分离代码。使用源码级别元数据的功能,你也可以在你的代码中加入 behavioral information (行为信息),在某种程度上类似于 .NET 属性。
  • spring-aspects 模块提供了集成使用 AspectJ。
  • spring-instrument 模块提供了类 instrumentation 的支持和在某些应用程序服务器使用类加载器实现。
  • spring-instrument-tomcat 用于 Tomcat Instrumentation 代理。

3、消息(Messaging)

spring-messaging 模块:Spring Framework 4 包含的模块,从 Spring 集成项目中抽象出来,比如 Message, MessageChannel, MessageHandler 及其他用来提供基于消息的基础服务。该模块还包括一组消息映射方法的注解,类似于基于编程模型 Spring MVC 的注解。

提供了对STOMP的支持,以及用于路由和处理来自WebSocket客户端的STOMP消息的注解编程模型。

4、数据访问/集成

Data Access/Integration 层由 JDBC, ORM, OXM, JMS, 和 Transaction 模块组成。

  • spring-jdbc 模块提供了不需要编写冗长的JDBC代码和解析数据库厂商特有的错误代码的JDBC-抽象层。
  • spring-tx 模块的支持可编程和声明式事务管理,用于实现了特殊的接口的和你所有的POJO类(Plain Old Java Objects)。
  • spring-orm 模块提供了流行的 object-relational mapping(对象-关系映射)API集成层,其包含 JPA,JDO,Hibernate。使用ORM包,你可以使用所有的 O/R 映射框架结合所有Spring 提供的特性,比如前面提到的简单声明式事务管理功能。
  • spring-oxm 模块提供抽象层用于支持 Object/XML mapping (对象/XML映射)的实现,如 JAXB、Castor、XMLBeans、JiBX 和 XStream 等。
  • spring-jms 模块(Java Messaging Service)包含生产和消费信息的功能。 从 Spring Framework 4.1 开始提供集成 spring-messaging 模块。

5、Web

Web 层由 spring-web, spring-webmvc, spring-websocket, 和 spring-webmvc-portlet 组成 。

  • spring-web 模块提供了基本的面向 web 开发的集成功能,例如多方文件上传、使用 Servlet listeners 和 Web 开发应用程序上下文初始化 IoC 容器。它也包含 HTTP 客户端以及 Spring 远程访问的支持的 web 相关的部分。
  • spring-webmvc 模块(也被称为 Web Servlet 模块)包含 Spring 的model-view-controller (模型-视图-控制器(MVC)和 REST Web Services 实现的Web应用程序。Spring 的 MVC 框架提供了domain model(领域模型)代码和 web form (网页) 之间的完全分离,并且集成了 Spring Framework 所有的其他功能。
  • spring-webmvc-portlet 模块(也被称为 Web-Portlet 模块)提供了MVC 模式的实现是用一个 Portlet 的环境和 spring-webmvc 模块功能的镜像。

spring-websocket:为web应用提供的高效通信工具。
Spring 4.0提供了一个名为spring-websocket的新模块,以支持基于WebSocket的、客户端-服务器的双向通信,它与JSR-356Java WebSocket API兼容。另外,还提供了基于SockJS(对WebSocket的模拟)的回调方案,以适应不支持WebSocket协议的浏览器。

6、Test

spring-test 模块支持通过组合 JUnit 或 TestNG 来进行单元测试和集成测试 。它提供了连续的加载 ApplicationContext 并且缓存这些上下文。它还提供了 mock object(模仿对象),您可以使用隔离测试你的代码。

IoC基础

IoC不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。

  • 谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;
    而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。

-为何是反转,哪些方面反转了:有反转就有正转,传统应用程序由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了

IoC和DI

DI

DI—Dependency Injection,即“依赖注入”:是组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。

  • 谁依赖于谁:当然是应用程序依赖于IoC容器;
  • 为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源;
  • 谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象;
  • 注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。

IoC和DI的关系

Dependency Injection 和 Inversion of Control 其实就是一个东西的两种不同的说法而已。本质上是一回事。

Dependency Injection 是一个程序设计模式和架构模型, 一些时候也称作 Inversion of Control,尽管在技术上来讲,Dependency Injection 是一个 Inversion of Control 的特殊实现,Dependency Injection 是指一个对象应用另外一个对象来提供一个特殊的能力,例如:把一个数据库连接以参数的形式传到一个对象的结构方法里面而不是在那个对象内部自行创建一个连接。

Inversion of Control 和 Dependency Injection 的基本思想就是把类的依赖从类内部转化到外部以减少依赖。 应用Inversion of Control,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。所以,Inversion of Control 是,关于一个对象如何获取他所依赖的对象的引用,这个责任的反转

控制反转和依赖注入的背景

“问题是,[他们]哪些方面的控制被反转?”这个问题由 Martin Fowler在他的 Inversion of Control (IoC) 网站在 2004 年提出。 Fowler 建议重新命名这个说法,使得他更加好理解,并且提出了 Dependency Injection(依赖注入) 这个新的说法。

IoC容器的概念

IoC容器就是具有依赖注入功能的容器,IoC容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。应用程序无需直接在代码中new相关的对象,应用程序由IoC容器进行组装。在Spring中BeanFactory是IoC容器的实际代表者。

Spring IoC容器如何知道哪些是它管理的对象呢?这就需要配置文件,Spring IoC容器通过读取配置文件中的配置元数据,通过元数据对应用中的各个对象进行实例化及装配。一般使用基于xml配置文件进行配置元数据,而且Spring与配置文件完全解耦的,可以使用其他任何可能的方式进行配置元数据,比如注解、基于java文件的、基于属性文件的配置都可以。

Bean的概念

由IoC容器管理的那些组成你应用程序的对象我们就叫它Bean, Bean就是由Spring容器初始化、装配及管理的对象,除此之外,bean就与应用程序中的其他对象没有什么区别了。那IoC怎样确定如何实例化Bean、管理Bean之间的依赖关系以及管理Bean呢?这就需要配置元数据,在Spring中由BeanDefinition代表。

容器内部,这些 bean 定义表示为 BeanDefinition 对象,其中包含(其他信息)以下元数据:

  • 限定包类名称:典型的实际实现是定义 bean 的类。
  • bean 行为配置元素,定义了容器中的Bean应该如何行为(范围、生命周期回调,等等)。
  • bean 需要引用其他 bean 来完成工作,这些引用也称为合作者或依赖关系。
  • 其他配置设置来设置新创建的对象,例如,连接使用 bean 的数量管理连接池,或者池的大小限制。

IoC容器到底是如何工作

  • 一、准备配置文件:就像前边Hello World配置文件一样,在配置文件中声明Bean定义也就是为Bean配置元数据。
  • 二、由IoC容器进行解析元数据: IoC容器的Bean Reader读取并解析配置文件,根据定义生成BeanDefinition配置元数据对象,IoC容器根据BeanDefinition进行实例化、配置及组装Bean。
  • 三、实例化IoC容器:由客户端实例化容器,获取需要的Bean。

Bean的作用域

什么是作用域呢?即“scope”,在面向对象程序设计中一般指对象或变量之间的可见范围。而在Spring容器中是指其创建的Bean对象相对于其他Bean对象的请求可见范围

Spring提供“singleton”和“prototype”两种基本作用域,另外提供“request”、“session”、“global session”三种web作用域;Spring还允许用户定制自己的作用域。

作用域 描述
单例(singleton) (默认)每一个Spring IoC容器都拥有唯一的一个实例对象
原型(prototype) 一个Bean定义可以创建任意多个实例对象
请求(request) 一个HTTP请求会产生一个Bean对象,也就是说,每一个HTTP请求都有自己的Bean实例。只在基于web的Spring ApplicationContext中可用
会话(session) 限定一个Bean的作用域为HTTPsession的生命周期。同样,只有基于web的Spring ApplicationContext才能使用
全局会话(global session) 限定一个Bean的作用域为全局HTTPSession的生命周期。通常用于门户网站场景,同样,只有基于web的Spring ApplicationContext可用
应用(application) 限定一个Bean的作用域为ServletContext的生命周期。同样,只有基于web的Spring ApplicationContext可用

The singleton scope

单例Bean全局只有一个共享的实例,所有将单例Bean作为依赖的情况下,容器返回将是同一个实例。

Spring的单例Bean和与设计模式之中的所定义的单例模式是有所区别的。设计模式中的单例模式是将一个对象的作用域硬编码的,一个ClassLoader只有唯一的一个实例。 而Spring的单例作用域,是基于每个容器,每个Bean只有一个实例。这意味着,如果开发者根据一个类定义了一个Bean在单个的Spring容器中,那么Spring容器会根据Bean定义创建一个唯一的Bean实例。 单例作用域是Spring的默认作用域,下面的例子是在基于XML的配置中配置单例模式的Bean。

The prototype scope

非单例的,原型的Bean指的就是每次请求Bean实例的时候,返回的都是新实例的Bean对象。也就是说,每次注入到另外的Bean或者通过调用getBean()来获得的Bean都将是全新的实例。 这是基于线程安全性的考虑,如果使用有状态的Bean对象用原型作用域,而无状态的Bean对象用单例作用域。

与其他的作用域相比,Spring是不会完全管理原型Bean的生命周期的:Spring容器只会初始化,配置以及装载这些Bean,传递给Client。但是之后就不会再去管原型Bean之后的动作了。 也就是说,初始化生命周期回调方法在所有作用域的Bean是都会调用的,但是销毁生命周期回调方法在原型Bean是不会调用的。所以,客户端代码必须注意清理原型Bean以及释放原型Bean所持有的一些资源。 可以通过使用自定义的bean post-processor来让Spring释放掉原型Bean所持有的资源。
在某些方面来说,Spring容器的角色就是取代了Java的new操作符,所有的生命周期的控制需要由客户端来处理。

依赖注入方式

构造函数----强依赖时

Setter方法---可选依赖时

AOP

目标:开发时把业务逻辑与非业务逻辑分离,运行时可以将两部分整合。

no-aop缺点

  • 代码重复
  • 耦合业务逻辑与非业务逻辑

AOP优点

  • 代码重用
  • 解耦业务逻辑与非业务逻辑

AOP术语

enter description here
AOP术语结构图

Aspect: 日志,安全等功能。
Join point:函数执行或属性访问
Advice:在某个函数执行点上要执行的切面功能
PointCut:匹配横切目标函数的表达式--即寻找哪些业务函数需要aop

Advice类型

before:函数执行之前
After returning:函数正常返回之后
After throwing:函数抛出异常之后
After finally:函数返回之后
Aroud:函数执行前后

Spring AOP

非完整AOP实现,整合AOP与IoC

XML schema-based AOP
配置集中
@AspectJ annotation-based AOP
配置分散,兼容AspectJ

注解方式:使用@AspectJ

1、 启用对@AspectJ的支持

Spring默认不支持@AspectJ风格的切面声明,使用如下配置:

Spring就能发现@AspectJ风格的切面并且将切面应用到目标对象。

2、声明切面

 

然后将该切面在配置文件中声明为Bean后,Spring就能自动识别并进行AOP方面的配置:

 

该切面就是一个POJO,可以在该切面中进行切入点及通知定义,如代码中的注释。

XML schema-based AOP

在Spring配置文件中,所以AOP相关定义必须放在aop:config标签下,该标签下可以有aop:pointcutaop:advisoraop:aspect标签,配置顺序不可变。
aop:pointcut:用来定义切入点,该切入点可以重用;
aop:advisor:用来定义只有一个通知和一个切入点的切面;
aop:aspect:用来定义切面,该切面可以包含多个切入点和通知,而且标签内部的通知和切入点定义是无序的;和advisor的区别就在此,advisor只包含一个通知和一个切入点。

附录

参考资料

Spring Framework Reference Documentation

Spring Framework 4.x参考文档

跟我学Spring3

Spring核心框架体系结构

Spring框架4.0 GA版本发布

网易JavaWbe微专业

延伸

POJO
比较分析 Spring AOP 和 AspectJ 之间的差别

参与评论