Spring 是一个轻量级的企业级应用开发框架,它于2004年发布第一个版本,其目的是用于简化企业级应用程序的开发。java
在传统应用程序开发中,一个完整的应用是由一组相互协做的对象组成,开发一个应用除了要开发业务逻辑以外,更多的是关注如何使这些对象协做来完成所需功能,并且要高内聚,低耦合。虽然一些设计模式能够帮咱们达到这个目的,但是这又徒增了咱们的负担。若是能经过配置的方式来建立对象,管理对象之间依赖关系,那么就可以减小许多工做,提升开发效率。Spring 框架主要就是来完成这个功能的。spring
Spring 框架除了帮咱们管理对象及其依赖关系以外,还提供了面向切面编程的能力,在此基础上,容许咱们对一些通用任务如日志记录、安全控制、异常处理等进行集中式管理,还能帮咱们管理最头疼的数据库事务。此外,它还提供了粘合其余框架的能力,使咱们能够方便地与各类第三方框架进行集成,并且不论是 Java SE 应用程序仍是 JavaEE 应用程序均可以使用这个平台进行开发。数据库
Spring 是基于 IoC 和 AOP 两大思想理论衍生而来的,能够说,Spring是一个同时实现了 IoC 和 AOP 的框架。编程
Spring 的总体架构如图所示:设计模式
核心模块只有3个:Beans、Core、和 Context ,它们构建起了整个 Spring 的骨架,没有它们就不可能有 AOP、Web 等上层的特性功能。若是在它们3个中选出一个最核心的模块的话,那就非 Beans 模块莫属了,其实 Spring 就是面向 Bean 的编程(BOP, Bean Oriented Programming),Bean 在 Spring 中才是真正的主角。关于 Bean 的观念,会在后面进行介绍。安全
IoC(Inverse Of Control,控制反转)是一种设计思想,目标是实现解耦。所谓控制反转,是指对资源的控制方式反转了。这里说的资源主要指咱们的业务对象,对象之间每每会存在某种依赖关系,当一个对象依赖另外一个对象时,传统的作法是在它内部直接 new 一个出来,即由对象本身负责建立并管理它所依赖的资源,这是传统的对资源的控制方式。IoC 就是将其颠倒过来,对象由主动控制所需资源变成了被动接受,由第三方(IoC 容器)对资源进行集中管理,对象须要什么资源就从IoC容器中取,或者让容器主动将所需资源注入进来。数据结构
IoC 以后,对象与所需资源之间再也不具备强耦合性,资源能够被直接替换,而无需改动需求方的代码。举个例子,董事长须要一个秘书,传统的作法是,董事长本身去指定一个秘书,控制权在他本身手上,可是这会致使他与秘书之间的耦合性较强,一旦想换秘书了,就得修改本身的代码。IoC 的作法是,董事长声明本身须要一个秘书,由IoC 容器为他指定一个秘书,至因而哪一个秘书,男的仍是女的,一切由容器说了算,若是要换秘书,也是修改容器的配置文件,与董事长无关,这样就实现了二者间的解耦。架构
IoC 的两种实现方式:框架
Java Bean 的概念不一样于 Bean,Java Bean 是指符合 JavaBeans 规范的一种特殊的 Bean,即:全部属性均为 private,提供 getter 和 setter,提供默认构造方法。JavaBean 也能够认为是遵循特定约定的POJO。post
POJO(Plain Ordinary Java Object)是指简单和普通的 Java 对象。严格来讲,它不继承类,不实现接口,不处理业务逻辑,仅用于封装数据。
首先配置 Bean 信息,向 Spring 的 IoC 容器(或简称 Spring 容器)中注册 Bean。以 XML 方式为例,以下配置了两个 Bean,其中第一个依赖第二个:
<bean id="John" class="Person"> <property name="lover"> <ref bean="Mary"/> </property> </bean> <bean id="Mary" class="Person"/>
而后建立 Spring 容器,同时绑定配置文件。以下:
ApplicationContext container = new ClassPathXmlApplicationContext("bean-config.xml");
而后经过容器的 getBean 方法便可获得咱们在配置文件中所配置的 Bean 的实例。以下:
Person John = container.getBean("John");
Spring 提供了两种 IoC 容器: BeanFactory 和 ApplicationContext 。
二者在核心功能上的区别主要是默认的加载策略不一样,这点区别几乎能够忽略不计,一般状况下,咱们老是使用更为强大的 ApplicationContext,不多会直接使用 BeanFactory。
如下是几个最经常使用的 ApplicationContext 实现类:
既然是容器,那它最底层确定是一个数据结构。经过跟踪 getBean 方法,咱们发现它是从一个叫做 singletonObjects 的 Map 集合中获取 Bean 实例的。singletonObjects 的定义以下:
能够判定,它就是 Spring 容器的核心,凡是做用域为单例的 Bean 的实例都保存在该 Map 集合中,我把它称之为单例池。
那么 getBean 方法作了哪些事情呢?
getBean 方法首先会从单例池中获取 Bean 实例,若是取到了就直接返回,不然,若是有父容器,尝试从父容器中获取,若是也没获取到,则建立实例。建立实例以前先确保该 Bean 所依赖的 Bean 所有初始化,而后,若是是原型 Bean,建立好实例后直接返回,若是是单例 Bean,建立好实例后将其放进单例池,而后再从单例池中获取并返回。
当 Spring 容器被建立时,它又是如何完成初始化的呢?
以 ClassPathXmlApplicationContext
为例,它的构造方法主要作的事情就是调用 refresh() 方法。
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 准备好本身 prepareRefresh(); // 建立并初始化BeanFactory ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 准备好要使用的BeanFactory prepareBeanFactory(beanFactory); try { // 对BeanFactory进行后置处理 postProcessBeanFactory(beanFactory); // 调用BeanFactory的后置处理器 invokeBeanFactoryPostProcessors(beanFactory); // 注册Bean的后置处理器 registerBeanPostProcessors(beanFactory); // 初始化消息源 initMessageSource(); // 初始化事件多播器 initApplicationEventMulticaster(); // 初始化其余特殊的bean onRefresh(); // 检测并注册监听器Bean registerListeners(); // 实例化其他全部(非懒加载)的单例Bean finishBeanFactoryInitialization(beanFactory); // 最后一步:发布相应的事件 finishRefresh();
refresh() 方法的主要执行流程:
refreshBeanFactory()
方法,该方法会首先新建或重建 BeanFactory 对象,而后使用相应的BeanDefinitionReader
读取并解析 Bean 定义信息,将每一个 Bean 定义信息依次封装成 BeanDefinition
对象,并将这些 BeanDefinition
对象注册到 BeanDefinitionRegistery
。这一步,完成了 BeanFactory 的建立,以及 Bean 定义信息的加载。finishBeanFactoryInitialization()
方法,该方法会遍历以前注册到 BeanDefinitionRegistery
中的全部 BeanDefinition
,依次实例化那些非抽象非懒加载的单例 Bean,并将其加入单例池。这一步,完成了 Bean 的实例化。Spring 容器的几个核心类:
DefaultListableBeanFactory
是一个通用的 BeanFactory
实现类,它还同时实现了BeanDefinitionRegistry
接口。从 ApplicationContext 实现类的源码中能够看到,在它内部维护着一个 DefaultListableBeanFactory
的实例,全部的 IoC 服务都委托给该 BeanFactory 实例来执行。BeanDefinitionRegistry
负责维护 BeanDefinition
实例,该接口主要定义了registerBeanDefinition()
、getBeanDefinition()
等方法,用于注册和获取 Bean 信息。BeanDefinition
用于封装 Bean 的信息,包括类名、是不是单例Bean、构造方法参数等信息。每个 Spring Bean 都会有一个 BeanDefinition
的实例与之相对应。BeanDefinitionReader
负责读取相应配置文件中的内容并将其映射到 BeanDefinition
,而后将映射后的 BeanDefinition
实例注册到 BeanDefinitionRegistry
,由 BeanDefinitionRegistry
来保管它们。我的理解,注册与装配是不一样的两个过程。注册指的是将 Bean 归入 IoC 容器。装配指的是创建 Bean 之间的依赖关系。
Bean 的注册方式有如下三种:
@ComponentScan
、@Component
等注解进行配置Bean 的装配分为手动装配和自动装配。
手动装配一样有三种方式:
@Resource
等注解来配置。
自动装配也称自动注入,有两种开启方式:
<bean>
标签中配置default-autowire
属性,或在@Bean
注解中配置autowire
属性。开启了默认自动装配的 Bean,Spring 会对它的所有属性都尝试注入值,这种方式不安全,所以不多使用。@Autowired
等注解对单个属性开启自动装配。Spring 支持如下四种用于自动装配的注解:
@Autowired
注解@Inject
注解@Resource
注解@Value
注解,用于装配 String 和基本类型的值。@Value
注解常常配合 SpEL 表达式一块儿使用。SpEL 表达式的主要语法:
${}
,表示从 Properties 文件中读取相应属性的值。一般须要同@PropertySource
注解配合使用,该注解用于指定从哪一个 Properties 文件中读取属性。#{}
,表示从 Spring Bean 中读取相应属性的值。如,#{user1.name}表示从名称为 user1 的 Bean 中 读取 name 属性值。:
用于指定默认值,如${server.port:80}。未完待续