Spring四、Spring IOC、DI、MVC、AOP时序图
最近一直在研究Spring IOC、DI、AOP、MVC几个步骤的源码,画出几种的时序图,方便以后查看回忆源码
1、IOC容器初始化
IOC 容器的初始化包含了BeanDefinition资源文件Resource定位、解析加载和注册三个步骤。
步骤依次为 : 读取资源文件为InputStream --> 转为Resource -> Document -> 解析元素节点封装为 BeanDefinition
-> 放入IOC容器中,即DefaultListableBeanFactory的 Map<String, BeanDefinition> beanDefinitionMap
主要的几个类
BeanFactory : BeanFactory及其子类也就是我们说的IOC容器,Spring提供了多种IOC容器以供选择
ListableBeanFactory接口表示Bean可列表化、HierarchicalBeanFactory接口表示Bean有继承关系、AutowireCapableBeanFactory定义自动装配;
以上三个接口的默认实现均为 org.springframework.beans.factory.support.DefaultListableBeanFactory
BeanDefinition : 描述Bean在资源文件中的配置信息及相互关系
BeanDefinitionReader : 解析资源为BeanDefinition
1.1 基于xml的Ioc容器初始化
入口:
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class IoCTest {
public static void main(String[] args) {
//
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
applicationContext.getBean("myUser");
}
}
IOC实现流程及原理
1.2 基于web的Ioc容器初始化
入口: web Ioc容器初始化由DispatcherServlet.init()方法开始
DispatcherServlet.init() 其实是调用的父类 org.springframework.web.servlet.HttpServletBean#init方法,之后
-> org.springframework.web.servlet.FrameworkServlet#initServletBean
-> org.springframework.web.servlet.FrameworkServlet#initWebApplicationContext
-> org.springframework.web.servlet.FrameworkServlet#configureAndRefreshWebApplicationContext
-> org.springframework.context.support.AbstractApplicationContext#refresh
-> org.springframework.context.support.AbstractApplicationContext#obtainFreshBeanFactory
到此,余下 web Ioc容器的初始化步骤和 XML IOC容器的初始化都经由 AbstractApplicationContext#obtainFreshBeanFactory 来完成,和上面时序图一样。
1.3 基于注解的Ioc容器初始化
component-scan 扫描指定包路径,解析class头的注解,及注解名称,封装为BeanDefinition;之后反射获取属性及value,封装为PropertyValue,赋值给BeanDefinition,最后放入Spring IOC容器中。
2、DI依赖注入时序图
入口: org.springframework.context.support.ClassPathXmlApplicationContext#getBean(java.lang.String)
-> org.springframework.context.support.AbstractApplicationContext#getBean(java.lang.String)
实现原理: 反射为属性赋值,如果存在循环依赖,使用三级缓存来处理:
一级缓存: 类成功实例化,属性也成功赋值
二级缓存: 类成功实例化,属性存在循环依赖、不能赋值
三级缓存: 类不能成功实例化 (指定使用构造器方法进行实例化,构造器中的参数存在循环引用)
在初始化完毕,会先遍历三级缓存进行依赖注入,放入一级缓存;然后遍历二级缓存,放入一级缓存;
3、AOP时序图
入口: org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)
实现逻辑:
基于JDK或者Cglib的动态代理通过字节码重组实现;
首先加载配置的切面PointCut及方法拦截通知Advice的配置,在进行依赖注入时,为每个类及类的每个方法正则匹配是否符合切面表达式,符合的话判断该类是否实现了接口,实现接口的话使用JDK的动态代理,否则使用Cglib的动态代理字节码重组重新织入通知代码,以次生产新的代理类。
AdvisedSupport -> AopConfig -> Advice -> JDKProxy or CglibProxy
4、MVC流程时序图
入口: DispatcherServlet.init() && DispatcherServlet.doService()
实现逻辑:
首先程序启动初始化Spring九大组件:
初始化url映射HandlerMapping; 扫描Controller下的所有RequestMapping,组成正则类型的url Pattern,并与Controller、method绑定关系组成HandlerMapping对象;
初始化参数适配器HandlerAdapter;记录RequestMapping对应method的参数类型,参数名称,RequestParam绑定名称等
初始化视图解析器ViewResolver;
....
之后再页面url发出请求后,根据请求url正则匹配到对应1到多个HandlerMapping,然后找出对应的参数适配器HandlerAdapter,反射进行方法调用返回ModelAndView,再由ViewResolver进行解析、占位符替换,最后对View渲染,将html或jsp通过Response返回
DispatcherServlet -> HandlerMapping -> HandlerAdapter -> ModelAndView -> ViewResolver -> View