Spring
简介
Spring是一个轻量级的IOC和AOP容器框架,是为Java应用程序提供基础性服务的一套框架,目的是简化企业应用程序的开发,使开发者只需关心业务需求,将对象之间的依赖关系交由框架处理,减低组件的耦合性。
核心模块
- Spring Core:核心类库,所有功能都依赖与它,主要组件是BeanFactory,提供IOC(控制反转)和DI(依赖注入)服务。
- Spring Contenxt:提供上下文信息,框架式Bean访问方式,以及企业级功能(JNDI、定时任务、添加国际化的使用、事件传播等)。
- Spring AOP: 提供面向切面的编程功能。
- Spring Web:提供基本面向Web的综合特性,提供对常见框架(Struts2,SpringMVC)的支持,能够管理这些框架,将Spring资源注入其中,也能在这些框架前后添加拦截器。
- Spring MVC :提供面向Web应用的MVC三层架构(Model-View-Controller)。
- Spring Dao:操作数据库模块,对JDBC的抽象封装,简化数据库访问异常处理,并能统一管理JDBC事务。
- Spring ORM:对现有ORM(Object Relational Mapping对象关系映射)框架的支持。
SpringAOP
spring启动流程
配置形式:5.2.12.RELEASE
- 启动代码
1 | ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationConfig.xml"); |
- ClassPathXmlApplicationContext内部
1 | //先加载ContextClosedEvent类 |
- 初始化AbstractApplicationContext 父类
1 | public AbstractApplicationContext( ApplicationContext parent){ |
- 调用refresh()正真初始化IOC
1 |
|
注解加载
三级缓存
BeanWrapper及类型转换
BeanWrapper其实就是一个Bean的包装器,它对Bean包装的目的是为了能操纵Bean中的属性,所以它同时需要具备获取、设置Bean中的属性能力,所以它也必须是一个属性访问器(PropertyAccessor),另外为了将各种不同类型的配置数据绑定到Bean的属性上,那么它还得具备属性转换的能力,因为它还得是一个类型转换器(TypeConverter)。
Spring中将类型转换的功能都委托给了一个TypeConverterDelegate,这个委托类在进行类型转换时会有两套方案:
- PropertyEditor,这是Spring最初提供的方案,扩展了java中的PropertyEditor(java原先提供这个接口的目的更多是为了进行图形化编程)。
- Spring后来提供的一个进行类型转换的ConversionService体系,用来取代PropertyEditor,因为PropertyEditor有很大的局限性,只能进行String->Object的转换。
Spring容器加载Bean流程
ResourceLoader从配置文件中加载Spring配置信息,并使用Resource表示这个配置文件的资源。
XXXBeanDefinitionReader(XXX可以是Xml、Properties、Annotated根据不同配置类型选择),读取并解析Resource所指向的配置文件,生成BeanDefinition对象(用于存储配置元信息:创建对象所需要的必要信息)。如xml配置中一个< bean >< /bean >标签话就对应一个BeanDefinition对象。所有的BeanDefinition对象会被注册到BeanDefinitionRegistry(底层使用key-value存储,如下)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21public class SimpleBeanDefinitionRegistry extends SimpleAliasRegistry implements BeanDefinitionRegistry {
/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);
//……
}
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
//……
/** Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
//……
}
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
//直接操作DefaultListableBeanFactory的方法
private final DefaultListableBeanFactory beanFactory;
}容器扫描BeanDefinitionRegistry中的BeanDefinition,利用反射识别出实现BeanFactoryPostProcessor工厂后置处理接口的Bean。并调用工厂后置处理器对BeanDefinition进行加工处理。
注:BeanFactoryPostProcessor是容器启动阶段Spring提供的一个扩展点,主要负责对注册到BeanDefinationRegistry中BeanDefination进行一定程度上的修改与替换。主要完成以下两项工作:
将配置文件中的占位符”${xx}”替换为最终配置值。
通过Java反射机制找出所有实现java.beans.PropertyEditor接口的Bean,并自动将它们注册到Spring容器的属性编辑器注册表中(PropertyEditorRegistry)。
Spring容器从BeanDefinitionRegistry中取出加工后的BeanDefinition,调用InstantiationStrategy类将其实例化。
在实例化Bean时,Spring容器会使用BeanWrapper对Bean进行封装。(BeanWrapper提供了很多以Java反射机制操作Bean的方法,它将结合该Bean的BeanDefinition以及容器中属性编辑器,完成Bean属性的设置工作)
最后利用容器中注册的Bean后处理器(实现BeanPostProcessor接口的Bean)对已经完成属性设置工作的Bean进行后续加工,直接装配出一个准备就绪的Bean。
Bean实例化执行流程。
@Resource与@Autowried区别
相同
- 都可以标注在字段或属性的setter方法上,都可以实现对象注入。
不同
- @Autowired 注解是按类型装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它required属性为false。
- @Resource注解默认按名称装配。名称可以通过@Resource的name属性指定,如果没有指定,则默认取字段的名称作为bean名称寻找依赖对象。当注解标注在属性的setter方法上时,默认取属性名作为bean名称寻找依赖对象。 若设置了type属性则按照类型注入。
- @Resources是JDK自带的,@Autowired是Spring提供的。
BeanFactory与FactoryBean区别
BeanFactory是IOC容器或对象工厂,FactoryBean是个Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。但对FactoryBean而言,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似 。
Spring中要获取FactoryBean实例的话需要在名字前面加&(注:BeanFactory.FACTORY_BEAN_PREFIX = “&”)。
1 | /**。 |
Spring常见面试题总结
SpringMVC
参数解析绑定
- SpringMVC初始化时,RequestMappingHandlerAdapter类会把一些默认的参数解析器添加到argumentResolvers中。当SpringMVC接收到请求后首先根据url查找对应的HandlerMethod。
- 遍历HandlerMethod的MethodParameter数组。
- 根据MethodParameter的类型来查找确认使用哪个HandlerMethodArgumentResolver,遍历所有的argumentResolvers的supportsParameter(MethodParameter parameter)方法。如果返回true,则表示查找成功,当前MethodParameter,使用该HandlerMethodArgumentResolver。这里确认大多都是根据参数的注解以及参数的Type来确认。
- 解析参数,从request中解析出MethodParameter对应的参数,这里解析出来的结果都是String类型。
- 转换参数,把对应String转换成具体方法所需要的类型,这里就包括了基本类型、对象、List、Set、Map。
MyBatis
二级缓存
执行流程
- 读取 MyBatis 配置文件:mybatis-config.xml 为 MyBatis 的全局配置文件,配置了 MyBatis 的运行环境等信息,例如数据库连接信息。
- 加载映射文件。映射文件即 SQL 映射文件,该文件中配置了操作数据库的 SQL 语句,需要在 MyBatis 配置文件 mybatis-config.xml 中加载。mybatis-config.xml 文件可以加载多个映射文件,每个文件对应数据库中的一张表。
- 构造会话工厂:通过 MyBatis 的环境等配置信息构建会话工厂 SqlSessionFactory。
- 创建会话对象:由会话工厂创建 SqlSession 对象,该对象中包含了执行 SQL 语句的所有方法。
- Executor 执行器:MyBatis 底层定义了一个 Executor 接口来操作数据库,它将根据 SqlSession 传递的参数动态地生成需要执行的 SQL 语句,同时负责查询缓存的维护。
- MappedStatement 对象:在 Executor 接口的执行方法中有一个 MappedStatement 类型的参数,该参数是对映射信息的封装,用于存储要映射的 SQL 语句的 id、参数等信息。
- 输入参数映射:输入参数类型可以是 Map、List 等集合类型,也可以是基本数据类型和 POJO 类型。输入参数映射过程类似于 JDBC 对 preparedStatement 对象设置参数的过程。
- 输出结果映射:输出结果类型可以是 Map、 List 等集合类型,也可以是基本数据类型和 POJO 类型。输出结果映射过程类似于 JDBC 对结果集的解析过程。
其他知识链接
SpringBoot
启动流程
1 | public class SpringbootApplication { |
WebApplicationType.deduceFromClasspath()
1 | static WebApplicationType deduceFromClasspath() { |
run方法
1 | public ConfigurableApplicationContext run(String... args) { |