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()


目录
相关文章
|
10月前
|
XML 安全 Java
使用 Spring 的 @Aspect 和 @Pointcut 注解简化面向方面的编程 (AOP)
面向方面编程(AOP)通过分离横切关注点,如日志、安全和事务,提升代码模块化与可维护性。Spring 提供了对 AOP 的强大支持,核心注解 `@Aspect` 和 `@Pointcut` 使得定义切面与切入点变得简洁直观。`@Aspect` 标记切面类,集中处理通用逻辑;`@Pointcut` 则通过表达式定义通知的应用位置,提高代码可读性与复用性。二者结合,使开发者能清晰划分业务逻辑与辅助功能,简化维护并提升系统灵活性。Spring AOP 借助代理机制实现运行时织入,与 Spring 容器无缝集成,支持依赖注入与声明式配置,是构建清晰、高内聚应用的理想选择。
858 0
|
9月前
|
XML Java 数据格式
《深入理解Spring》:AOP面向切面编程深度解析
Spring AOP通过代理模式实现面向切面编程,将日志、事务等横切关注点与业务逻辑分离。支持注解、XML和编程式配置,提供五种通知类型及丰富切点表达式,助力构建高内聚、低耦合的可维护系统。
|
11月前
|
设计模式 Java 开发者
如何快速上手【Spring AOP】?从动态代理到源码剖析(下篇)
Spring AOP的实现本质上依赖于代理模式这一经典设计模式。代理模式通过引入代理对象作为目标对象的中间层,实现了对目标对象访问的控制与增强,其核心价值在于解耦核心业务逻辑与横切关注点。在框架设计中,这种模式广泛用于实现功能扩展(如远程调用、延迟加载)、行为拦截(如权限校验、异常处理)等场景,为系统提供了更高的灵活性和可维护性。
1429 0
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
947 0
|
存储 开发框架 前端开发
[回馈]ASP.NET Core MVC开发实战之商城系统(五)
经过一段时间的准备,新的一期【ASP.NET Core MVC开发实战之商城系统】已经开始,在之前的文章中,讲解了商城系统的整体功能设计,页面布局设计,环境搭建,系统配置,及首页【商品类型,banner条,友情链接,降价促销,新品爆款】,商品列表页面,商品详情等功能的开发,今天继续讲解购物车功能开发,仅供学习分享使用,如有不足之处,还请指正。
544 0
|
开发框架 前端开发 .NET
[回馈]ASP.NET Core MVC开发实战之商城系统(三)
[回馈]ASP.NET Core MVC开发实战之商城系统(三)
392 0
|
开发框架 前端开发 .NET
[回馈]ASP.NET Core MVC开发实战之商城系统(一)
[回馈]ASP.NET Core MVC开发实战之商城系统(一)
647 0
|
SQL 开发框架 前端开发
[回馈]ASP.NET Core MVC开发实战之商城系统(开篇)
[回馈]ASP.NET Core MVC开发实战之商城系统(开篇)
600 0
|
开发框架 缓存 JSON
ASP.NET Core MVC 从入门到精通之Filter
ASP.NET Core MVC 从入门到精通之Filter
608 0