1.Spring 整体架构说明
1.1 整体架构
1.2 核心容器
组成: spring-beans、 spring-core、 spring-context、springexpression(SpringExpressionLanguage,SpEL)
spring-core
主要包含Spring 框架基本的核心工具类,Spring 的其他组件都要用到这个包里的类,Core 模块是其他组件的基本核心
spring-beans(BeanFactory)
它包括访问配置文件、创建和管理Bean ,以及进行 Inversion of Control I Dependency Injection ( IoC/DI )操作相关的所有类
BeanFactory 接口是Spring 框架中的核心接口,它是工厂模式的具体体现。BeanFactory 使用控制反转对应用程序的配置和依赖性规范与实际的应用程序代码进行了分离。但 BeanFactory 容器实例化后并不会自动实例化Bean,只有当 Bean 被使用时,BeanFactory 容器才会对该 Bean 进行实例化与依赖关系的装配。
spring-context
模块框架与核心模块之上,它扩展了BeanFactory,为它添加了bean生猛周期控制、框架事件体系以及资源加载透明化等功能,此外,模块还提供了许多企业级支持,如邮件访问、远程访问、任务调度等
ApplicationContext 是该模块的核心接口,它的超类是 BeanFactory 。与BeanFactory 不同的是,ApplicationContext 容器实例化后会自动对所有的单例bean进行实体化与依赖关系的装配,使之处于待用状态。(使用BeanFacotry的bean是延时加载的,ApplicationContext是非延时加载的)
spring-expression
模块是统一表达式语言(EL)的扩展模块,可以查询、管理运行中的对象,同时也方便的可以调用对象方法、操作数组、集合等。它的语法类似于传统EL,但提供了额外的功能,最出色的要数函数调用和简单字符串的模板函数。这种语言的特性是基于Sprin*品的需求而设计,他可以非常方便地同Spring IOC 进行交互。
1.3 AOP 和设备支持
组成: spring-aop、spring-aspects 、spring-instrument
spring-aop
是Spring 的另一个核心模块,是AOP 主要的实现模块。作为继OOP 后,对程序员影响最大的编程思想之一,AOP极大地开拓了人们对于编程的思路。
在Spring 中,他是以JVM的 动态代理技术 为基础,然后设计出了一系列的AOP横切实现,比如前置通知、返回通知、异常通知等,同时,Pointcut接口来匹配切入点,可以使用现有的切入点来设计横切面,也可以扩展相关方法根据需求进行切入。
spring-aspects
模块集成自AspectJ框架,主要是为Spring AOP提供多种AOP 实现方法。
spring-instrument
模块是基于JAVA SE中的"java.lang.instrument"进行设计的,应该算是AOP的一个支援模块。主要作用是在JVM启用时,生成一个代理类,程序员通过代理类在运行时修改类的字节,从而改变一个类的功能,实现AOP 的功能。
1.4 数据访问与集成
组成:spring-jdbc、spring-tx、spring-orm、spring-jms、spring-oxm
spring-jdbc
主要是提供JDBC模板方式、关系数据库对象化方式、SimpleJdbc方式、事务管理来简化JDBC编程。主要实现类是JdbcTemplate、SimpleJdbcTemplate以及NamedParameterJdbcTemplate。
spring-tx
是Spring JDBC事务控制实现模块。
使用Spring框架,它对事务做了很好的封装,通过它的AOP配置,可以灵活的配置在任何一层。但是在很多的需求和应用,直接使用JDBC事务控制还是有其优势的。其实,事务是以业务逻辑为基础的;一个完整的业务应该对应业务层里的一个方法;如果业务操作失败,则整个事务回滚;所以,事务控制是绝对应该放在业务层的;但是,持久层的设计则应该遵循一个很重要的原则:保证操作的原子性,即持久层里的每个方法都应该是不可以分割的。所以,在使用Spring JDBC事务控制时,应该注意其特殊性。
spring-orm
是ORM 框架支持模块,主要集成 Hibernate, Java Persistence API (JPA) 和Java Data Objects (JDO) 用于资源管理、数据访问对象(DAO)的实现和事务策略。如 JPA、 JDO、 Hibernate、 iBatis 等,提供了 一个交互层。 利用 ORM 封装包,可以混合使用所 有 Spring 提供的特性进行 O/R 映射, 如前边提到的简单声明性事务管理。
spring-jms
JavaMessagingService 能够发送和接收信息,自SpringFramework4.1以后,他还提供了对spring-messaging模块的支撑。
spring-oxm
主要提供一个抽象层以支撑OXM(OXM是Object-to-XML-Mapping的缩写,它是一个O/M-mapper,将java对象映射成XML数据,或者将XML数据映射成java对象),例如:JAXB, Castor, XMLBeans, JiBX 和 XStream等。
1.5 WEB 组件
组成:spring-web、spring-webmvc、spring-websocket 、spring-webflux
spring-web
为Spring提供了最基础Web支持,主要建立于核心容器之上,通过Servlet或者Listeners 来初始化IOC 容器,也包含一些与Web相关的支持。
spring-webmvc
众所周知是一个的Web-Servlet模块,实现了Spring MVC(model-view-Controller)的Web应用。
spring-websocket
主要是与Web前端的全双工通讯的协议。
spring-webflux
一个新的非堵塞函数式 Reactive Web 框架,可以用来建立异步的,非阻塞,事件驱动的服务。并且扩展性非常好。
2 Spring 核心IOC容器原理
2.1 接口设计
2.1.1 BeanFactory
BeanFactory
通过上面的接口设计图我们可以看到,在Spring当中最基本的IOC容器接口是BeanFactory,这个接口当中定义作为一个IOC容器最基本的一些操作和功能,下来看看它的源码:
package org.springframework.beans.factory;
import org.springframework.beans.BeansException;
import org.springframework.core.ResolvableType;
/**
* BeanFactory作为最原始同时也最重要的Ioc容器,
* 它主要的功能是为依赖注入 (DI) 提供支持.
* 这里定义的只是一系列的接口方法,通过这一系列的BeanFactory接口,
* 可以使用不同的Bean的检索方法很方便地从Ioc容器中得到需要的Bean,
* 从而忽略具体的Ioc容器的实现,从这个角度上看,
* 这些检索方法代表的是最为基本的容器入口。
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Chris Beams
* @since 13 April 2001
*/
public interface BeanFactory {
/**
* 转定义符"&" 用来引用实例,或把它和工厂产生的Bean区分开,
* 就是说,如果一个FactoryBean的名字为a,
* 那么,&a会得到那个Factory *
* FactoryBean和BeanFactory 是在Spring中使用最为频繁的类,
* 它们在拼写上很相似。一个是Factory,也就是Ioc容器或对象工厂;
* 一个是Bean。
* 在Spring中,所有的Bean都是由BeanFactory(也就是Ioc容器)
* 来进行管理的。
* 但对FactoryBean而言,这个Bean不是简单的Bean,
* 而是一个能产生或者修饰对象生成的工厂Bean,
* 它的实现与设计模式中的工厂模式和修饰器模式类似。
*/
String FACTORY_BEAN_PREFIX = "&";
/**
* 五个不同形式的getBean方法,获取实例
* @param name 检索所用的Bean名
* @return Object(<T> T) 实例对象
* @throws BeansException 如果Bean不能取得
*/
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
/**
* 让用户判断容器是否含有指定名字的Bean.
* @param name 搜索所用的Bean名
* @return boolean 是否包含其中
*/
boolean containsBean(String name);
/**
* 查询指定名字的Bean是否是Singleton类型的Bean.
* 对于Singleton属性,可以在BeanDefinition指定.
* @param name 搜索所用的Bean名
* @return boolean 是否包是Singleton
* @throws NoSuchBeanDefinitionException 没有找到Bean
*/
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
/**
* 查询指定名字的Bean是否是Prototype类型的。
* 与Singleton属性一样,可以在BeanDefinition指定.
* @param name 搜索所用的Bean名
* @return boolean 是否包是Prototype
* @throws NoSuchBeanDefinitionException 没有找到Bean
*/
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
/**
* 查询指定了名字的Bean的Class类型是否是特定的Class类型.
* @param name 搜索所用的Bean名
* @param typeToMatch 匹配类型
* @return boolean 是否是特定类型
* @throws NoSuchBeanDefinitionException 没有找到Bean
*/
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
/**
* 查询指定名字的Bean的Class类型.
* @param name 搜索所用的Bean名
* @return 指定的Bean或者null(没有找到合适的Bean)
* @throws NoSuchBeanDefinitionException 没有找到Bean
*/
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
/**
* 查询指定了名字的Bean的所有别名,这些都是在BeanDefinition中定义的
* @param name 搜索所用的Bean名
* @return 指定名字的Bean的所有别名 或者一个空的数组
*/
String[] getAliases(String name);
}
通过上面的接口说明我们看到在BeanFactory里面只对IOC容器最基本的行为做了定义,而不关心Bean是怎样定义和加载的。如果我们想要知道一个工厂具体生产对象的过程,就需要去看这个接口的实现类,在Spring当中实现这个接口的有很多子类,下面我们来看看其一个常用的实现类XmlBeanFacotry的代码吧
package org.springframework.beans.factory.xml;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.core.io.Resource;
/**
* XmlBeanFactory是BeanFactory的最简单实现类
*
* XmlBeanFactory的功能是建立在DefaultListableBeanFactory
* 这个基本容器的基础上的,并在这个基本容器的基础上实行了其他诸如
* XML读取的附加功能。
* XmlBeanFactory使用了DefaultListableBeanFactory作为基础类,
* DefaultListableBeanFactory是一个很重
* 要的Ioc实现
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Chris Beams
* @since 15 April 2001
*/
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
/**
* 根据给定来源,创建一个XmlBeanFactory
* @param resource Spring中对与外部资源的抽象,
* 最常见的是对文件的抽象,特别是XML文件。而且Resource里面通常
* 是保存了Spring使用者的Bean定义,
* 比如applicationContext.xml在被加载时,
* 就会被抽象为Resource来处理。
* @throws BeansException 载入或者解析中发生错误
*/
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
/**
* 根据给定来源和BeanFactory,创建一个XmlBeanFactory
* @param resource Spring中对与外部资源的抽象,
* 最常见的是对文件的抽象,特别是XML文件。而且Resource里面通常
* 是保存了Spring使用者的Bean定义,
* 比如applicationContext.xml在被加载时,
* 就会被抽象为Resource来处理。
* @param parentBeanFactory 父类的BeanFactory
* @throws BeansException 载入或者解析中发生错误
*/
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
}
测试代码:
public static void main(String[] args) {
ClassPathResource resource = new ClassPathResource("META-INF/beans.xml");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(resource);
User user = factory.getBean("user", User.class);
System.out.println(user.getName()+" : "+user.getAge());
}
XML 资源文件 bean,xml
<bean id="user1" name="user1" class="com.yanxiao.ioc.User">
<property name="name" value="yanxiao"></property>
<property name="age" value="20"></property>
</bean>
DefaultListableBeanFactory
是 BeanFactory 的一个默认实现类。器实例对象可以作为一个独立使用的IOC 容器。可以认为该对象是容纳bean 对象的容器
( DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); )
我们定义好的bean 经过Spring 的载入和加载等处理后,最终交由该工厂管理,在需要得到bean 的时候便可以向他获取。
2.1.2 BeanDefinition
BeanDefinition 是对所有bean 进行已成抽象的统一,把形式格样的对象统一封装成一个便于Spring 内部进行协调管理和调度的数据结构,BeanDefinition 屏蔽了不同对象对于Spring 框架的差异。
BeanDefinition 包括了bean 的所有信息,包括 类名、scope、属性、构造函数、参数列表、依赖bean 、是否单例、是否懒加载等。后面对bean 的操作其实就是对BeanDdfinition 的操作,例如拿到BeanDefinition 后可以根据里边的类名、构造器、构造函数参数,使用反射进行对象创建。
总结: 在spring中,我们配置的bean 经过载入、解析和注册 这三个过程后,在框架内部被封装成BeanDefinition 这种类型。最终所有的BeanDefinition 交由BeanFactory 中的definitionMap 统一管理。
2.1.3 spring 支持的bean scope
Spring bean 支持 5 种 scope:
- Singleton - 每个 Spring IoC 容器仅有一个单实例。
- Prototype - 每次请求都会产生一个新的实例。
- Request - 每一次 HTTP 请求都会产生一个新的实例,并且该 bean 仅在当前 HTTP 请求内有效。
- Session - 每一次 HTTP 请求都会产生一个新的 bean,同时该 bean 仅在当前 HTTP session 内有效。
- Global-session - 类似于标准的 HTTP Session 作用域,不过它仅仅在基于 portlet 的 web 应用中才有意义。Portlet 规范定义了全局 Session 的概念,它被所有构成某个 portlet web 应用的各种不同的 portlet 所共享。在 global session 作用域中定义的 bean 被限定于全局 portlet Session 的生命周期范围内。如果你在 web 中使用 global session 作用域来标识 bean,那么 web 会自动当成 session 类型来使用。
仅当用户使用支持 Web 的 ApplicationContext 时,最后三个才可用。
2.1.4 BeanFactory 和 ApplicationContext
BeanFactory | ApplicationContext |
---|---|
它使用懒加载 | 它使用即时加载 |
它使用语法显式提供资源对象 | 它自己创建和管理资源对象 |
不支持国际化 | 支持国际化 |
不支持基于依赖的注解 | 支持基于依赖的注解 |