Spring IOC、DI、AOP以及Spring MVC面试原理(1)

简介: Spring IOC、DI、AOP以及Spring MVC面试原理(1)

Spring IOC加载流程:

初始化ApplicationContext;ApplicationContext实现类中完成的

通过BeanDefinitionReader加载配置文件,并封装成BeadDefinition

将BeanDefinition包装成BeanWrapper

将BeanWrapper保存至IOC容器中


(1)读取配置文件:通过ResourceLoader的getResource方法将类路径,URL,文件系统等方式读为Resource

(2)解析配置文件:解析是在BeanDefinitionReader中完成的,最常用的类是XMLBeanDefinitionReader来完成的,解析涉及到很多步骤,最常见的是将XML文件读取成Document文档,DefaultBeanDefinitionDocumentReader对Document对象进一步解析,DefaultBeanDefinitionDocumentReader又委托给BeanDefinitionParserDelegate进行解析,如果是标准的XML Namespace元素,则会委托合适的NameSpaceHandler进行解析最终解析的结果封装为BeanDefinitionHolder至此解析完成。

(3)Bean的注册:bean的注册是在BeanFactory里完成的,BeanFactory最常见的一个实现类是DefaultListableBeanFactory,,它实现了BeanDefinitionRegistry接口,所以其中的registerBeanDefinition()方法,可以对BeanDefinition进行注册这里附带一提,最常见的XmlWebApplicationContext不是自己持有BeanDefinition的,它继承自AbstractRefreshableApplicationContext,其持有一个DefaultListableBeanFactory的字段,就是用它来保存BeanDefinition所谓的注册,其实就是将BeanDefinition的name和实例,保存到一个Map中。刚才说到,最常用的实现DefaultListableBeanFactory,其中的字段就是beanDefinitionMap,是一个ConcurrentHashMap。

(4)实例化:注册也完成之后,在BeanFactory的getBean()方法之中,会完成初始化,也就是依赖注入的过程


Spring DI加载流程:

Spring DI的基本流程:

(1)循环读取BeanDefinition的缓存信息

(2)调用getBean方法创建对象实例

(3)将创建好的对象实例包装BeanWrapper对象

(4)将BeanWrapper对象缓存到IOC容器

(5)循环IOC容器执行注入


实例化策略根据配置实现不同的策略,将其封装为BeanWrapper

SimpleInstantiationStrategy

实例化有两种情况?

目标类配置了AOP,实例化对象代理类

目标类没有配置AOP,实例化原生对象


为什么要使用BeanWrapper?

统一一个对外访问对象的入口

扩展一些功能,缓存一些配置信息


DI原理:

**FactoryBean.getBeans()**触发依赖注入

createBeanInstance->用反射创建了对象实例->封装成BeanWrapper();

populateBean()–>根据beanName、BeanDefinition、BeanWrapper找到需要赋值的属性,把需要


赋值的属性封装为一个集合,集合的元素是PropertyValue,PropertyValue保存了需要赋值的Bean,赋值需要调用的方法,要赋什么值。


applyPropertyValues() 循环PropertyValue,挨个调用BeanWrapper的setValue()方法,用反射代用setter方法完成赋值。


DI是依赖注入,当IOC容器完成初始化后,针对非懒加载的Bean进行依赖注入或者当第一次getBean时


1)实例化 通过反射机制实例化Bean


2)依赖注入 判断其field是否有需要被注入的属性,如果有则进行注入该依赖的Bean属性


3) 循环依赖的问题,可以通过多级缓存来解决,二级缓存,三级缓存


Spring循环依赖三级缓存是否可以去掉第三级缓存?


image.png


BeanFactory是ApplicationContext的父类


BeanFactory与FactoryBean的区别:

BeanFactory是管理Bean的工厂

FactoryBean是创建对象的工厂Bean


Spring AOP面向切片编程:

基本概念:

(1)切面(Aspect)

 切面是一个横切关注点的模块化,一个切面能够包含同一个类型的不同增强方法,比如说事务处理和日志处理可以理解为两个切面。切面由切入点和通知组成,它既包含了横切逻辑的定义,也包括了切入点的定义。 Spring AOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的连接点中。


(2) 目标对象(Target)

 目标对象指将要被增强的对象,即包含主业务逻辑的类对象。或者说是被一个或者多个切面所通知的对象。


(3) 连接点(JoinPoint)

 程序执行过程中明确的点,如方法的调用或特定的异常被抛出。连接点由两个信息确定:


方法(表示程序执行点,即在哪个目标方法)

相对点(表示方位,即目标方法的什么位置,比如调用前,后等)

 简单来说,连接点就是被拦截到的程序执行点,因为Spring只支持方法类型的连接点,所以在Spring中连接点就是被拦截到的方法。

(4) 切入点(PointCut)

 切入点是对连接点进行拦截的条件定义。切入点表达式如何和连接点匹配是AOP的核心,Spring缺省使用AspectJ切入点语法。

 一般认为,所有的方法都可以认为是连接点,但是我们并不希望在所有的方法上都添加通知,而切入点的作用就是提供一组规则(使用 AspectJ pointcut expression language 来描述) 来匹配连接点,给满足规则的连接点添加通知。


(5) 通知(Advice)

 通知是指拦截到连接点之后要执行的代码,包括了“around”、“before”和“after”等不同类型的通知。Spring AOP框架以拦截器来实现通知模型,并维护一个以连接点为中心的拦截器链。


前置通知(Before)指某连接点之前执行的通知,但这个通知不能阻止连接点之前的代码的执行。

后置通知(After)指当某连接点退出时执行的通知(无论是正常返回还是异常退出)

返回后通知(After Return Advice)是某个连接点正常完成通知后执行的通知,不包括抛出异常的情况。

环绕通知(Around Advice)围绕在连接点前后,比如一个方法调用前后

异常通知(After Throwing Advice)是在方法抛出异常导致退出时执行的通知。

(6) 织入(Weaving)

 织入是将切面和业务逻辑对象连接起来, 并创建通知代理的过程。织入可以在编译时,类加载时和运行时完成。在编译时进行织入就是静态代理,而在运行时进行织入则是动态代理。


(7) 增强器(Adviser)

 Advisor是切面的另外一种实现,能够将通知以更为复杂的方式织入到目标对象中,是将通知包装为更复杂切面的装配器。Advisor由切入点和Advice组成。

 Advisor这个概念来自于Spring对AOP的支撑,在AspectJ中是没有等价的概念的。Advisor就像是一个小的自包含的切面,这个切面只有一个通知。切面自身通过一个Bean表示,并且必须实现一个默认接口。

 简单来讲,整个 aspect 可以描述为: 满足 pointcut 规则的 joinpoint 会被添加相应的 advice 操作。


两个步骤

AOP的入口:AOP的入口是由接入BeanPostProcessor后置处理器开始的,在bean初始化后提供回调入口,在AbstractAutowireCapableBeanFactory中initializeBean()方法中添加BeanPostProcessor后置处理器。


创建代理类:1,PostProcessAfterInitialization()方法中调用了wrapIfNecessary(),如果代理类实现了接口,使用JDK动态代理,如果没有实现接口,使用cglib动态代理。


代码织入:1,在JDK动态代理类中,如果动态代理类会实现InvokeHandler接口重写invoke方法,在Invoke方法中会通过getInterceptorsAndDynamicInterceptionAdvice方法从提供的配置实例config中获取Advisor列表,遍历处理这个Advisor切面,如果是PointCutAdvisor,则判断此Advisor能否应用到目标方法Method上,将满足条件的Advisor通过AdvisorAdapter转化为MethodInterceptor拦截器列表返回。接下来在Invoke中判断拦截器是否为空,如果为空,则直接调用Method.Invoke反射方法,如果拦截器列表不为空,则调用ReflectiveMethodInvocation.proceed()方法触发执行链的执行,Proceed()串其了整个Interceptor调用链。


image.png


两个重要的类:intercept 拦截器,责任链组件 invoke()

invocation 调用器,嗲用通知回调的组件,procceed()


目录
相关文章
|
21天前
|
Android开发 移动开发 小程序
binder机制原理面试,安卓app开发教程
binder机制原理面试,安卓app开发教程
binder机制原理面试,安卓app开发教程
|
1天前
|
存储 Java C++
理解SpringIOC和DI第一课(Spring的特点),IOC对应五大注解,ApplicationContext vs BeanFactory
理解SpringIOC和DI第一课(Spring的特点),IOC对应五大注解,ApplicationContext vs BeanFactory
|
2天前
|
存储 前端开发 Java
Spring IoC&DI(3)—DI详解
Spring IoC&DI(3)—DI详解
8 0
|
2天前
|
存储 Java 程序员
Spring IoC&DI(2)—IoC详解
Spring IoC&DI(2)—IoC详解
10 2
|
3天前
|
Java Spring
【JavaEE进阶】 Spring AOP源码简单剖析
【JavaEE进阶】 Spring AOP源码简单剖析
|
3天前
|
Java Spring
【JavaEE进阶】 Spring AOP详解
【JavaEE进阶】 Spring AOP详解
|
3天前
|
数据采集 Java 程序员
【JavaEE进阶】 Spring AOP快速上手
【JavaEE进阶】 Spring AOP快速上手
|
8天前
|
Java Spring
|
9天前
|
Java Spring
|
9天前
|
前端开发 Java Maven
Spring AOP
Spring AOP
18 1