Spring框架概述
一、Spring的意义
Spring是致力于全方位简化Java开发的框架,任何Java应用都能在简单性、可测试性、松耦合等方面从Spring中获益。
1.Spring是如何简化Java开发的?
为降低Java开发的复杂性,Spring采取了以下4中关键性策略:
(1)基于POJO的轻量级和最小侵入性编程;
(2)通过依赖注入(DI)和面向接口实现松耦合;
(3)基于切面和惯例进行声明式编程;
(4)通过切面和模板减少样板式代码。
下面将逐一详细介绍。
2.基于POJO的轻量级和最小侵入性编程
(1)名词解释
POJO:简单Java对象,普通的JavaBeans(区别于EJB)。
POJO只包括JavaBean类规范所要求的内容,不允许有业务方法,也不能携带有connection之类的方法。主要用来指代那些没有遵从特定的Java对象模型、约定或框架(如EJB)的Java对象。
JavaBean:Java中,一种遵循特定写法的Java类,常用于JSP(用来封装数据)。包括POJO和EJB。
JavaBean类一般要遵守以下规则:
①必须具备一个无参数的构造函数
②所有属性必须private
③属性要提供public的getXxx或setXxx函数来访问
④必须实现Serializable接口
EJB:企业级JavaBeans,一种JavaEE服务器端组件模型,用于部署分布式应用程序。
在JavaBean规范的基础上,提出了更多复杂的要求。
(2)Spring策略
Spring的非侵入编程模型,不会强迫你的类实现Spring规范的接口、继承Spring规范的类。在Spring构建的应用中,你甚至根本看不出它是Spring的一个组件,它可以依旧是POJO。
3.通过依赖注入,保持对象之间松散耦合
(1)名词解释
依赖注入(DI):由系统中负责协调各对象的第三方组件,在创建对象的时候通过JavaBean属性(设值方法注入)或者构造函数(构造器注入),设定对象的依赖关系。【注意,是接收者依赖被接收者】
依赖注入会将所依赖的关系自动交给目标,而不是让它自己去获取依赖。也就是说,目标并不需要自己去创建其他类的对象,而是直接接收对象。并且,目标往往是与接口耦合,只要接收的对象实现了某个接口就可以。这样,就能由依赖注入随意更换接收的对象,进一步松耦合。
依赖注入的另一个好处是:方便测试。紧耦合的目标难以测试,而通过依赖注入,可以让一个测试类实现耦合接口,然后不用修改代码,就可以让目标接收测试对象了。
装配:创建应用组件之间协作的行为。换句话说,就是把对象交给接收者的行为。
(2)Spring策略
①Spring常见装配bean的方式之一:采用XML装配。
具体做法:在.xml文件中,将接收者和被接收者声明为Spring中的bean。在接收者的bean声明中,构造器参数传入被接收者的引用。然后,在程序中创建Spring中对应的对象,来加载Spring上下文,获取目标对象(接收者bean)。
②Spring装配bean的方式之二:使用Java描述配置。
具体做法:创建一个配置类,至少包括两个函数:
a.一个返回值类型为被接收者接口类型的函数,返回要传给接收者的对象;
b.一个返回值类型为接收者接口类型的函数,接收a函数返回的对象,以此创建接收者对象并返回。
4.基于切面进行声明式编程
(1)名词解释
面向切面编程(AOP):为促使软件系统实现关注点的分离的一项技术,将遍布应用各处的功能分离出来,形成可重用的组件。
横切关注点:诸如日志、事务管理和安全这样的系统服务,经常融入到自身具有核心业务逻辑的组件中去,把这些系统服务称为横切关注点。
作用:AOP将横切关注点模块化,在需要的组件中以声明的方式应用。组件只需要关注自身的业务代码,甚至根本不知道那些横切关注点的存在。这样,就避免了横切关注点的功能(代码或是方法调用)在各个组件中反复出现、使得组件变得混乱而复杂的缺陷,确保了POJO的简单性。
(2)Spring策略
在.xml文件中,将横切关注点声明为切面。
具体做法:在上述.xml文件中,先将横切关注点声明为Spring中的bean,然后通过<aop:config>配置切面:先在<aop:aspect>中引用该bean,用<aop:pointcut>定义切入点(各组件中需要用到横切关注点的地方),用<aop:before>定义切入点前的行为(前置通知),用<aop:after>定义切入点后的行为(后置通知)。
如此,各个组件(业务组件、横切关注点)都不需要任何其他代码,只需要通过配置.xml文件,就能达成在业务组件中使用横切关注点的目的。
5.使用模板消除样板式代码
(1)名词解释
样板式代码:通常为了实现通用的和简单的任务,使用API时,需要不断地重复编写类似的代码。
例如:Jdbc中,需要先连接数据库,然后创建语句对象,然后进行业务操作(比如获取对象),最后关闭数据库,其中还要用try-catch捕捉异常。然而,其中只有业务操作是不同的,其他部分都是重复的样板式代码。
(2)Spring策略
Spring旨在通过模板封装来消除样板式代码,使用模板后,只需写出核心业务逻辑即可,无需迎合具体API的需求。
例如,上述的Jdbc代码(函数),在Spring中由JdbcTemplate替代:函数直接return JdbcTemplate.queryForObject(...);,在括号中写入核心业务逻辑(SQL查询语句,RowMapper对象,和数个查询参数)即可。
二、Spring容器
容器是Spring框架最核心的部分。在基于Spring的应用中,应用对象生存于Spring容器中:Spring容器负责创建对象、装配它们、配置并管理它们的整个生命周期,从new到finalize()。Spring容器使用DI、管理构成应用的组件,它会创建相互协作的组件之间的关联。
1.Spring容器的使用
Spring容器主要分为两种不同的类型:
bean工厂是最简单的容器,提供基本的DI支持。(bean工厂是由org.springframework.beans.factory.BeanFactory接口定义的)
应用上下文(ApplicationContext)基于BeanFactory构建,提供应用框架级别的服务。(应用上下文是由org.springframework.context.ApplicationContext接口定义的)
前者太过低级,实用性不高,实际上使用较多的是后者。下面简单介绍一下应用上下文的使用。
常用的几种类型的应用上下文有:
(1)AnnotationConfigApplicationContext:从一个或者多个基于Java的配置类中加载Spring应用上下文。
(2)AnnotationConfigWebApplicationContext:从一个或者多个基于Java的配置类中加载Spring Web应用上下文。
(3)ClassPathXmlApplicationContext:从classpath路径中的一个或多个xml配置文件中加载上下文定义,把应用上下文的定义文件作为类资源。
(4)FileSystemXmlApplicationContext:从文件系统下的一个或多个xml配置文件中加载上下文定义。
(5)XmlWebApplicationContext:从Web应用下的一个或多个xml配置文件中加载上下文定义。
从Java配置类中加载应用上下文,是由一个有完整包名的Java类,创建一个对象。比如:
ApplicationContext con = new AnnotationConfigApplicationContext(cn.cage.test.ConfigText);
从classpath路径和文件系统中加载应用上下文,是在对应的文件路径下,找到xml文件,创建一个对象即可。比如:
ApplicationContext con = new ClassPathXmlApplicationContext("abc.xml");
加载完应用上下文后,就可以调用con.getBean()方法,从Spring容器中获取bean。
2.Spring中bean的生命周期
bean装载到Spring上下文中一个典型的生命周期过程如下:
>创建阶段
(1)Spring对bean实例化(创建对象);
(2)Spring将值和bean的引用注入到bean(对象)对应的属性中。
>初始化阶段
(3)名称设定:
如果bean实现了BeanNameAware接口,Spirng将bean的ID传给setBeanName()方法(接口中的方法);
(4)容器传入:
如果bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入;
如果bean实现了ApplicationContextAware接口,Spirng将调用setApplicationContext()方法,将bean所在的应用上下文的引用传入;
(5)其他初始化:
如果bean实现了BeanPostProcessor接口,Spring将调用它们的postProcessBeforeInitialization()方法,并在初始化方法调用(下一条↓)之后,调用postProcessAfterInitialization()方法;
如果bean实现了InitializingBean接口,或使用init-method声明了初始化方法,Spring将调用它们的afterPropertiesSet()方法;
>使用阶段
(6)bean被应用程序使用。期间一直驻留在应用上下文中,直至该应用上下文被销毁。
>销毁阶段
(7)如果bean实现了DisposableBean接口,或使用destroy-method声明了销毁方法,Spring将调用它的destroy()方法。
三、Spring功能概述
1.Spring模块(Spring核心框架)
下载的Spring版本中,有几十个模块。其中,每个模块分为3个jar文件:二进制类库jar,源码jar,和JavaDoc的jar。这些模块按功能可以分为六类,如下图所示:
下面,简单介绍各模块:
(1)Spring核心容器
容器是Spring框架最核心的部分。所有的Spring模块都构建于核心容器之上,当你配置应用时,其实是在隐式地使用这些类。
比如,Spring核心容器中包括了Spring bean工厂,它为Spring提供了DI功能。基于bean工厂,还有多种Spring应用上下文的实现,每一种都提供了不同的配置Spring的方式。
(2)面向切面编程
这个模块是Spring中开发切面的基础。AOP的相关内容在上面刚刚提到过,这里就不多说了。
(3)数据访问与集成
Spring的JDBC和DAO模块抽象了样板式代码,使得操作数据库变得简单明了,还能避免一些安全问题。此外,该模块基于多种数据库服务的错误信息,构建了一个语义丰富的异常层,方便抛出合理的异常。
Spring还提供了ORM模块,并建立在对DAO的支持上,为多个ORM框架提供了构建DAO的简便方式。Spring中的ORM模块并非是新创建的,而是对许多流行的ORM框架进行了集成:Hibernate,Java Persistence API,Java Data Object,iBatis SQL Maps。
本模块同样包含了在JMS之上构建的Spirng抽象层,它会使用消息以异步的方式与其他应用集成。
(4)Web与远程调用
对于Web应用的构建,Spring提供了功能强大的Spring MVC框架,有助于在Web层提升应用的松耦合水平。
此外,Spring还提供了多种构建与其他应用交互的远程调用方案。Spring集成了RMI,Hessian,Burlap,JAX-WS,并且还自带了远程调用框架:HTTP invoker。Spring还提供了暴露和使用REST API的良好支持。
(5)Instrumentation
此模块提供了为JVM添加代理的功能。由于应用及其有限,此处不多介绍。
(6)测试
Spring为使用JNDI,Servlet和Portlet编写单元测试提供了一系列的mock对象实现。
对于集成测试,该模块为加载Spring应用上下文中的bean集合与bean进行交互提供了支持。
2.Spring Portfolio(扩展服务)
Spring Portfolio几乎为每个领域的Java开发都提供了Spring编程模型。具体内容太过庞杂,这里不多介绍,后期再进一步了解。