Spring原理及应用
-
- 1、Spring的特性
- 2、Spring的模块
- 3、Spring的核心JAR包
- 4、Spring的注解
- [5、Spring IoC的原理](#5、Spring IoC的原理)
-
- [5.1、Spring IoC简介](#5.1、Spring IoC简介)
- [5.2、Spring Bean的装配流程](#5.2、Spring Bean的装配流程)
- [5.3、Spring Bean的作用域](#5.3、Spring Bean的作用域)
-
- 5.3.1、Singleton
- 5.3.2、Prototype
- 5.3.3、Request
- 5.3.4、Session
- [5.3.5、Global Session](#5.3.5、Global Session)
- [5.4、Spring Bean的生命周期](#5.4、Spring Bean的生命周期)
- 5.5、Spring的4种依赖注入
- 5.6、自动装配的5种方式
1、Spring的特性
Spring基于J2EE技术实现了一套轻量级的Java WebService系统应用框架。它有很多优秀的特性,很多公司都选择把Spring作为产品或项目的基础开发架构。Spring的特性包括轻量、控制反转(Inversion of Control,IoC)、面向容器、面向切面(Aspect OrientedProgramming,AOP)和框架灵活,具体如图所示。

1.1、轻量
从JAR包的大小上来说,Spring是一个轻量级的框架,其核心JAR包spring-web-5.2.0.RELEASE.jar和spring-core-5.2.0.RELEASE.jar的大小均为1.4MB左右;从系统的资源使用上来说,Spring也是一个轻量级的框架,其运行期间只需要少量的操作系统资源(内存和CPU)便能稳定运行。除此之外,Spring还是模块化的,应用程序在使用过程中可以根据需求引入模块(以JAR包依赖方式引入)来实现不同的功能,使其应用更加灵活。
1.2、控制反转
Spring的控制反转指一个对象依赖的其他对象将会在容器的初始化完成后主动将其依赖的对象传递给它,而不需要这个对象自己创建或者查找其依赖的对象。Spring基于控制反转技术实现系统对象之间依赖的解耦。
1.3、面向容器
Spring实现了对象的配置化生成和对象的生命周期管理,因此,可以理解为其是面向容器的。通过Spring的XML文件或者注解方式,应用程序可以配置每个Bean对象被创建和销毁的时间,以及Bean对象创建的先后顺序和依赖关系。Spring中的实例对象可以是全局唯一的单例模式,也可以在每次需要时都重新生成一个新的实例,具体以哪种方式创建Bean对象由Bean的生命周期决定,通过prototype属性来定义。
1.4、面向切面
Spring提供了面向切面的编程支持,面向切面技术通过分离系统逻辑和业务逻辑来提高系统的内聚性。在具体的使用过程中,业务层只需要关注并实现和业务相关的代码逻辑,而不需要关注系统功能(例如系统日志、事务支持)和业务功能的复杂关系,Spring通过面向切面技术将系统功能自动织入业务逻辑的关键点。
1.5、框架灵活
基于容器化的对象管理技术,Spring中的对象可以被声明式地创建,例如通过XML文件或注解的方式定义对象和对象之间的依赖关系。Spring作为一个轻量级的J2EE Web框架,具有事务管理、持久化框架集成和Java Web服务等功能,应用程序可以根据需求引入相应的模块,以实现不同的功能。
2、Spring的模块
Spring为企业应用程序提供一站式服务。Spring是模块化的,允许应用按需引入各个模块。Spring提供的常用模块有核心容器层(Core Container)、数据访问层(DataAccess)、Web应用层(Web Access)。除此之外,Spring还包括AOP、Aspects、Instrumentation、Messaging和Test。Spring的模块如图所示。下面对Spring中各个核心的模块做简单的介绍。

2.1、核心容器层
核心容器层由Spring-Beans、Spring-Core、Spring-Context和SpEL(Spring Expression Language,Spring表达式语言)等模块组成。
2.1.1、Spring-Beans
Spring-Beans模块基于工厂模式实现对象的创建。Spring-Beans通过XML配置文件实现了声明式的对象管理,将对象之间复杂的依赖关系从实际编码逻辑中解耦出来。
2.1.2、Spring-Core
Spring-Core模块是Spring的核心功能实现,具体包括控制反转和依赖注入。所谓依赖注入,是指在一个Bean实例中引用另外一个Bean实例时,Spring容器会自动创建其所依赖的Bean实例,并将该Bean实例注入(传递)到对应的Bean中。
2.1.3、Spring-Context
Spring-Context模块是在Spring-Beans和Spring-Core模块的基础上构建起来的。Spring-Context模块继承自Spring-Beans模块,并且添加了国际化、事件传播、资源加载和透明地创建上下文等功能。
同时,Spring-Context模块提供了一些J2EE的功能,比如EJB、JMX和远程调用等。ApplicationContext接口是Spring-Context模块操作Bean的入口。
Spring-Context-Support提供了将第三方库集成到Spring-Context的支持,比如缓存(EhCache、Guava、JCache)、邮件(JavaMail)、调度(CommonJ、Quartz)和模板引擎(FreeMarker、JasperReports、Velocity)等。
2.1.4、SpEL
SpEL模块提供了丰富的表达式语言支持,用于在运行过程中查询和操作对象实例。SpEL在JSP 2.1表达式语言规范的基础上进行了扩展,支持set方法、get方法、属性赋值、方法调用、访问数组集合、索引内容、逻辑算术运算、命名变量、基于名称在Spring IoC容器检索对象,同时支持列表的投影、选择和聚合等功能。
2.2、数据访问层
数据访问层包括JDBC、ORM、OXM、JMS和事务处理模块。它们的术语描述如下表所示。

2.2.1、JDBC
JDBC模块提供了JDBC抽象层。Spring持久化层基于JDBC抽象层实现了在不同数据库之间灵活切换,而不用担心不同数据库之间SQL语法的不兼容。
2.2.2、ORM
ORM模块提供了对象关系映射API的集成,包括JPA(Java Persistence API)、JDO(Java Data Object)和Hibernate等。基于该模块,ORM框架能很容易地和Spring的其他功能(例如事务管理)整合。
2.2.3、OXM
OXM模块提供了对OXM实现的支持,比如JAXB、Castor、XML Beans、JiBX、XStream等。
2.2.4、JMS
JMS模块包含消息的生产(Produce)和消费(Consume)功能。从Spring 4.1开始,Spring集成了Spring-Messaging模块,用于实现对消息队列的支持。
2.2.5、事务处理
事务处理(Transactions)模块基于接口方式实现了声明式事务管理。编程式事务的实现需要应用程序调用相应的beginTransaction()、commit()、rollback()等方法来实现事务的管理,Spring声明式事务只需要通过注解或配置即可实现事务的管理,具体的事务管理工作由Spring自动处理,应用程序不需要关心事务的提交(Commit)和回滚(Rollback)。
2.3、Web应用层
Web应用层主要包含Web交互和数据传输等相关功能,由Web、Web-MVC、Web-Socket、Web-Portlet组成。
2.3.1、Web
Web模块不但提供了面向Web应用的基本功能,还提供了HTTP(Hyper Text Transfer Protocol,超文本传输协议)客户端及Spring远程调用中与Web相关的部分。Web模块基于Servlet监听器初始化IoC容器。
2.3.2、Web-MVC
Web-MVC模块为Web应用提供了模型视图控制(ModelView Controller,MVC)和REST API服务的实现。Spring的MVC框架使数据模型和视图分离,数据模型负责数据的业务逻辑,视图负责数据的展示。同时,Web-MVC可与Spring框架的其他模块方便地集成。
2.3.3、Web-Socket
Web-Socket模块提供了对WebSocket-Base的支持,用于实现在Web应用程序中服务端和客户端实时双向通信,尤其在实时消息推送中应用广泛。
2.3.4、Web-Portlet
Web-Portlet模块提供了基于Portlet环境的MVC实现,并提供了与Spring Web-MVC模块相关的功能。
2.4、其他重要模块
除了上述介绍的模块,Spring还有其他一些重要的模块,例如,AOP、Aspects、Instrumentation、Messaging和Test等。
2.4.1、AOP
AOP模块提供了面向切面的编程实现,允许应用程序通过定义方法拦截器和切入点来实现系统功能和业务功能之间的解耦。
2.4.2、Aspects
Aspects模块提供了Spring与AspectJ的集成,是一个面向切面编程的模块。
2.4.3、Instrumentation
Instrumentation模块在应用中提供了对Instrumentation的支持和类加载器的实现。
2.4.4、Messaging
Messaging模块为STOMP(Simple Text OrientatedMessaging Protocol,简单文本定向消息协议)提供了支 持,主要用于应用程序中WebSocket子协议的实现。同时,Messaging模块可通过注解的方式来选择和处理来自WebSocket客户端的STOMP消息。
2.4.5、Test
Test(测试)模块用于对JUnit或TestNG等测试框架提供支持,以实现Spring代码的自动化测试。
3、Spring的核心JAR包
Spring基于模块化实现,每个模块都对应不同的JAR包。要全面了解Spring,首先应从JAR包开始,但是SpringJAR包众多,每个包中又都含有复杂的技术原理,鉴于篇幅原因,下表对常用的JAR包和功能做了简单介绍,以便读者能够整体了解Spring的核心技术架构。


4、Spring的注解
Spring的注解将应用程序中Bean的定义和Bean之间复杂的依赖关系的配置从XML配置中解放出来,应用程序只需在需要某些服务或者功能时,使用注解依赖注入即可,具体Bean的定义和依赖关系由Spring的自动装配来完成。这使得Spring的使用更加方便。
4.1、Spring注解的使用
Spring注解的使用很简单,首先导入命名规范,然后指定IoC的扫描包,最后在Java类中直接使用注解依赖注入需要的资源即可。
4.1.1、导入命名空间及规范
在Spring的applicationContext.xml配置文件中导入命名空间及规范。代码如下。

4.1.2、配置扫描包
在applicationContext.xml配置文件中配置需要扫描的包。如下代码开启了自动扫描com.alex.spring包下的所有类,也就是说,只有在com.alex.spring包中的注解才能够生效。

完整的Spring注解配置文件如下。


4.1.3、使用注解
使用注解比较简单,直接在Java类中用@按需使用即可。具体代码如下。

4.2、Spring的常用注解
Spring的注解在开发中无处不在,常用注解如表所示。



5、Spring IoC的原理
5.1、Spring IoC简介
Spring通过一个配置文件描述Bean和Bean之间的依赖关系,利用Java的反射功能实例化Bean并建立Bean之间的依赖关系。Spring的IoC容器在完成这些底层工作的基础上,还提供了Bean实例缓存管理、Bean生命周期管理、Bean实例代理、事件发布和资源装载等高级服务。
5.2、Spring Bean的装配流程
Spring在启动时会从XML配置文件或注解中读取应用程序提供的Bean配置信息,并在Spring容器中生成一份相应的Bean配置注册表;然后根据这张注册表实例化Bean,装配好Bean之间的依赖关系,为上层业务提供基础的运行环境。其中Bean缓存池为HashMap实现。SpringBean的装配流程如图所示。

5.3、Spring Bean的作用域
Spring为Bean定义了5种作用域,分别为Singleton(单例)、Prototype(原型)、Request(请求级别)、Session(会话级别)和Global Session(全局会话)。
5.3.1、Singleton
Singleton是单例模式,当实例类型为单例模式时,Spring IoC容器中只会存在一个共享的Bean实例,无论有多少个Bean引用它,都始终指向同一个Bean对象。该模式在多线程下是不安全的。Singleton作用域是Spring中的默认作用域,也可以通过配置将Bean定义为Singleton模式,具体配置如下。

5.3.2、Prototype
Prototype是原型模式,每次通过Spring容器获取Prototype定义的Bean时,容器都将创建一个新的Bean实例,每个Bean实例都有自己的属性和状态,而Singleton全局只有一个对象。因此,对有状态的Bean经常使用Prototype作用域,而对无状态的Bean则使用Singleton作用域。具体配置如下。

5.3.3、Request
Request指在一次HTTP请求中容器会返回该Bean的同一个实例,而对不同的HTTP请求则会创建新的Bean实例,并且该Bean实例仅在当前HTTP请求内有效,当前HTTP请求结束后,该Bean实例也将会随之被销毁。具体配置如下。

5.3.4、Session
Session指在一次HTTP Session中容器会返回该Bean的同一个实例,而对不同的Session请求则会创建新的Bean实例,该Bean实例仅在当前Session内有效。和HTTP请求相同,每一次Session都会创建新的Bean实例,而不同的Bean实例之间不共享数据,且Bean实例仅在自己的Session内有效,请求结束,则Bean实例将随之被销毁。具体配置如下。

5.3.5、Global Session
Global Session指在一个全局的HTTP Session中容器会返回该Bean的同一个实例,且仅在使用Portlet Context时有效。
5.4、Spring Bean的生命周期
Spring Bean的生命周期执行过程如图所示。

- 实例化一个Bean。
- 按照Spring上下文对实例化的Bean进行配置。
- 如果这个Bean实现了BeanNameAware接口,则会调用它实现的setBeanName(String)方法,该方法传递的参数是Spring配置文件中Bean的id值。
- 如果这个Bean实现了BeanFactoryAware接口,则会调用它实现的setBeanFactory(BeanFactory)方法,该方法传递的参数是Spring工厂自身。
- 如果这个Bean实现了ApplicationContextAware接口,则会调用setApplication Context(ApplicationContext)方法,该方法传入的参数是Spring上下文。
- 如果该Bean关联了BeanPostProcessor接口,则会调用postProcessBefore Initialization(Object obj,String s)方法,该方法在Bean初始化前调用,常用于定义初始化Bean的前置工作,比如系统缓存的初始化。
- 如果Bean在Spring配置文件中配置了init-method属性,则会自动调用其配置的初始化方法。
- 如果某个Bean关联了BeanPostProcessor接口,将会调用postProcessAfter Initialization(Object obj,String s)方法。至此,Bean的初始化工作就完成了,应用程序就可以开始使用Bean实例了。
- 当Bean不再被需要时,会在清理阶段被清理掉。如果Bean实现了DisposableBean接口,则Spring会在退出前调用实现类的destroy()方法。
- 如果某个Bean的Spring配置文件中配置了destroy-method属性,在Bean被销毁前会自动调用其配置的销毁方法。
5.5、Spring的4种依赖注入
5.5.1、构造器注入
构造器注入指通过在类的构造函数中注入属性或对象来实现依赖注入。如下代码通过标签配置了一个id为persionDaoImpl的Bean,并通过标签在其构造函数中注入了一个message属性,注入完成后在类中可以直接通过this.message获取注入的属性值。

5.5.2、set方法注入
set方法注入是通过在类中实现get、set方法来实现属性或对象的依赖注入的。如下代码通过标签配置了一个id为persionDaoImpl的Bean,并通过标签在Bean中注入了一个id为123的属性值,注入完成后在类中可以直接使用getId()获取注入的属性。


5.5.3、静态工厂注入
静态工厂注入是通过调用工厂类中定义的静态方法来获取需要的对象的,为了让Spring管理所有对象,应用程序不能直接通过"工厂类.静态方法()"的方式获取对象,而需要通过Spring注入的方式获取。代码如下。

上述代码定义了一个DaoFactory工厂类和getStaticFactoryDaoImpl()静态工厂方法,该方法实例化并返回一个StaticFactoryDaoImpl实例;同时定义了一个SpringAction类,并通过setStaticFactoryDao获取注入的FactoryDao。具体的XML注入语法如下。

上述代码定义了一个name为staticFactoryDao的工厂类,并通过factory-method定义了实例化对象的方法,这里实例化对象的方法是一个名为getStaticFactoryDaoImpl的静态方法。该静态方法返回一个工厂类实例,在springAction中通过<property></property>标签注入静态工厂实例。
5.5.4、实例工厂注入
实例工厂注入指的是获取对象实例的方法是非静态的,因此首先需要实例化一个工厂类对象,然后调用对象的实例化方法来实例化对象。具体代码如下。

上述代码定义了一个name为factoryDao的工厂类,并通过factory-method定义了实例化对象的方法,这里实例化对象的方法是一个名为getFactoryDaoImpl的方法。该方法返回一个工厂类,在springAction中通过<property></property>标签注入工厂实例。
5.6、自动装配的5种方式
Spring的装配方式包括手动装配和自动装配。手动装配包括基于XML装配(构造方法、set方法等)和基于注解装配2种方式。自动装配包括5种装配方式,这5种方式均可以用来引导Spring容器自动完成依赖注入,具体如下。
- no:关闭自动装配,通过显式设置ref属性来进行对象装配。
- byName:通过参数名自动装配,Bean的autowire被设置为byName后,Spring容器试图匹配并装配与该Bean的属性具有相同名字的Bean。
- byType:通过参数类型自动装配,Bean的autowire被设置为byType后,Spring容器试图匹配并装配与该Bean的属性具有相同类型的Bean。
- constructor:通过设置构造器参数的方式来装配对象,如果没有匹配到带参数的构造器参数类型,则Spring会抛出异常。
- autodetect:首先尝试使用constructor来自动装配,如果无法完成自动装配,则使用byType方式进行装配。