根据学习《Spring实战》第四版整理。
1、 Spring简介
Spring的出现,根本上是为了全方位的简化Java开发。
其采取了4中关键策略:
- 基于POJO(Plain Old Java Object)的轻量级和最小侵入性编程;
- 通过依赖注入和面向接口实现松耦合;
- 基于切面和惯例进行声明式编程;
- 通过切面和模板减少样板式代码。
1.1 基于POJO的最小侵入性编程
Spring避免自身的API弄乱应用代码,因而不会强迫实现Spring规范的接口或继承Spring规范的类。Spring通过依赖注入(DI)来装备bean,使应用对象之间保持松耦合。
public class Student implements People{
private MathBook book;
public Student(){
this.book = new MathBook();
}
}
例如Student类,其构造函数中创建了MathBook,使得Student和MathBook耦合在一起。
而通过DI,对象之间的相互依赖关系由第三方组件在创建对象的时候进行设定,对象无需自行创建或管理它们的依赖关系,依赖关系将被自动注入到需要它们的对象当中去。
1.2 通过依赖注入和面向接口实现松耦合
public class Student implements People{
private Book book;
public Student(Book book){
this.book = book;
}
}
在构造的时候将book作为构造器参数传入,也是DI的方式之一,即构造器注入。
由于传入的类型为Book,是各类书都要实现的一个接口。因此,其各种实现类如MathBook、EnglishBook等任意的Book实现都能被响应。
由于Student没有与特征的Book实现发生耦合,所以也成为松耦合,即如果一个对象只通过接口(而不是具体实现或初始化过程)来表明依赖关系,那么这种依赖就能够在对象本身毫不知情的情况下,用不同的具体实现进行替换。
1.3 通过切面和惯例进行声明式编程
面向切面编程(AOP),可以将应用中各处的功能分离出来形成可重用的组件。
一般来说,系统由许多不同的组件组成,每一个组件各负责一块特定功能,而诸如日志、事务管理和安全这样的系统服务经常融入到自身具有核心业务逻辑的组件中去,这些系统服务通常被称为横切关注点。
而AOP能够将这些服务模块化,并以声明的方式将它们应用到它们需要影响的组件中。
public class Recorder {
private PrintStream printStream;
public Recorder(PrintStream printStream) {
this.printStream = printStream;
}
public void beforeLearn() {
printStream.println("before learning");
}
public void afterLearn() {
printStream.println("after learning");
}
}
如Recorder
类,其具有两个方法beforeLearn()
和afterLearn()
。在学习之前,会调用beforeLearn()
方法,同理,在学习之后,会调用afterLearn()
方法。其都是通过构造器注入进来,由PrintStrem
类来调用,
public class Student extends People{
private Learn learn;
private Recorder recorder;
public Student(Recorder recorder, Learn learn) {
this.recorder = recorder;
this.learn = learn;
}
public void study() {
recorder.beforeLearn();
learn.study();
recorder.afterLearn();
}
}
如上,在study()
方法执行前后,会先后执行beforeLearn()
和afterLearn()
方法。
而采用Spring AOP,通过XML配置或注解的方式,将Recorder
声明为一个Spring切面之后,无需显式的调用beforeLearn()
和afterLearn()
方法,即可达到同样的效果。
1.4 通过切面和模板减少样板式代码
在应用的开发过程中,经常会在不同的模块中编写重复的功能,这种通用的代码即称为样板式的代码。
2、Spring容器
在基于Spring的应用中,对象的整个生命周期都由Spring容器进行管理。
容器是Spring框架的核心,Spring容器使用依赖注入管理构成应用的组件,负责创建相互协作的组件之间的关联。
其中,Spring自带了多个容器的实现,分为两种不同的类型。
-
bean工厂
由
org.springframework.beans.factory.BeanFacotry
接口定义,是最简单的容器,提供基本的DI支持。 -
应用上下文
由
org.springframework.context.ApplicationContext
接口定义,基于BeanFactory创建,提供应用框架级别的服务。
2.1 应用上下文容器
Spring中自带了多种类型的应用上下文,具体如下。
AnnotationConfigApplicationContext
:从一个或多个基于Java的配置类中加载Spring应用上下文。AnnotationConfigWebApplicationContext
:从一个或多个基于Java的配置类中加载Spring Web应用上下文。ClassPathXmlApplicationContext
:从类路径下的一个或多个XML配置文件中加载上下文定义,把应用上下文的定义文件作为类资源。FileSystemXmlApplicationContext
:从文件系统下的一个或多个XML配置文件中加载上下文定义。XmlWebApplicationContext
:从Web应用下的一个或多个XML配置文件中加载上下文定义。
装载应用上下文的过程类似,如下使用ClassPathXmlApplicationContext
从类路径下加载应用上下文;
ApplicationContext context = new ClassPathXmlApplicationContext("test.xml");
在应用上下文准备就绪之后,就可以通过调用getBean()
方法从Spring容器中获取bean。
2.2 bean的生命周期
Spring容器中bean的声明周期详细描述如下:
- Spring对bean进行实例化;
- Spring将值和bean的引用注入到bean对应的属性中;
- 如果bean实现了
BeanNameAware
接口,Spring将bean的ID传递给setBeanName()
方法; - 如果bean实现了
BeanFactoryAware
接口,Spring将调用setBeanFactory()
方法,将BeanFactory容器实例传入; - 如果bean实现了
ApplicationContextAware
接口,Spring将调用setApplicationContext()
方法,将bean所在的应用上下文的引用传入进来; - 如果bean实现了
BeanPostProcessor
接口,Spring将调用它们的postProcessBeforeInitialization()
方法; - 如果bean实现了
InitializingBean
接口,Spring将调用它们的afterPropertiesSet()
方法。类似的,如果bean使用init-method
声明了初始化方法,该方法也会被调用; - 如果bean实现了
BeanPostProcessor
接口,Spring将调用它们的postProcessAfterInitialization()
方法; - 此时,bean已经准备就绪,可以被应用程序使用了,它们将一直驻留在应用上下文中,直到该应用上下文被销毁;
- 如果bean实现了
DisposableBean
接口,Spring将调用它的destroy()
接口方法。同样,如果bean使用destory-method
声明了销毁方法,该方法也会被调用。