spring源码-Ioc容器初始化、循环依赖、AOP、MVC

spring源码解析

spring核心理解

* spring 核心概念
	** IoC:控制反转,其实new对象的权利由使用者改为spring去创建。spring要想使用IoC去创建对象,必须使用到DI
	** DI:依赖注入,就是给new出来的对象设置成员变量。
	** AOP:就是将项目中的业务代码(提交订单)和系统代码(事务、记录日志)进行解耦,也是给业务代码进行功能增强的一种途径。
		*** AOP是和OOP一样,都是编程思想
		*** AOP的实现都有哪些呢?
			**** spring aop
			**** AspectJ
			**** spring 整合 AspectJ
	** BOP:面向Bean的编程。在spring中一切都是针对Bean设计和编程的。
		*** Bean被spring通过IoC和DI进行创建和管理。
		*** Bean被spring通过AOP进行功能增强。
		*** Bean其实就是对应bean标签和@Bean注解的类
	** 基础容器:IoC容器、【BeanFactory接口】(DefaultListableBeanFactory)
	** 高级容器:【ApplicationContext接口】,实现了BeanFactory接口,只是在该接口之外,新加了一些高级功能,本质是还是一个BeanFactory。
		*** 高级容器和基础容器的区别
			**** 高级容器对于bean实例的加载时机是项目启动时。(饿汉式加载)
			**** 基础容器对于bean实例的加载时机是第一次被需要时。(懒汉式加载)
	** 循环依赖(A--->B ......   B--->A)
		***	构造方法的循环(无法解决)
			public A{ 
				private B b;
				public A(B b){
					this.b = b;
				}
			}
			
			public B{ 
				private A a;
				public B(A a){
					this.a = a;
				}
			}				
		*** 	set方法的循环(spring中可以通过缓存去解决掉)
			public A{ 
				private B b;
				public setB(B b){
					this.b = b;
				}
			}
			
			public B{ 
				private A a;
				public setA(A a){
					this.a = a;
				}
			}				
* spring中使用简单工厂模式去管理bean的分析
	public BeanFactory{
		public Object getBean(String name){
			if ("cat".equals(name)) {
				return new Cat();
			} else if ("dog".equals(name)) {
				return new Dog();
			} else if ("cow".equals(name)) {
				return new Dog();
			} else {
				return null;
			}

		}
	}

spring Ioc 理解

在这里插入图片描述
BeanDefintion: 存储bean标签的信息(id,class,init-method)scope信息(单例、多例)

TypedStringValue:存储的是peoperty标签的value值(带有类型含义)

RuntimeBeanReference:存储的是property标签的ref值(指向另一个对象)

PropertyValue:存储的property标签的信息

BeanFarory体系

在这里插入图片描述

|-- BeanFactory 是Spring bean容器的根接口.
|-- – AutowireCapableBeanFactory 提供工厂的装配功能。
|-- – HierarchicalBeanFactory 提供父容器的访问功能
|-- – -- ConfigurableBeanFactory 如名,提供factory的配置功能,眼花缭乱好多api
|-- – -- – 集大成者,提供解析,修改bean定义,并初始化单例.
|-- – ListableBeanFactory 提供容器内bean实例的枚举功能.这边不会考虑父容器内的实例.

BeanDefintionRegistry 提供对于BeanDefinition集合的访问

SingletonDefintionRegistry 访问单例bean实例集合的接口

容器初始化流程源码

以doxxx开头的重点读

获取bean实例

【XmlBeanFactory】#getBean
	|--【AbstractBeanFactory】#doGetBean
	  |--transformedBeanName 获取bean名称
	  |--getSingleton #从缓存中获取单例bean 依次 一级、二级、三级缓存查找  第一次进来的时候是获取不到的 isSingletonCurrentlyInCreation 正在创建的beanName是没有的 singletonsCurrentlyInCreation集合为空
	  |--xxx
	  |--getMergedLocalBeanDefinition 获取要实例化的bean的BeanDefinition对象
	  |--checkMergedBeanDefinition 检查该beanDefinition对象对应的Bean是否是抽象的
	  |--【DefaultSingletonBeanRegistry】#getSingleton 获取单例bean bean的创建 以及set集合放数据
		|-- beforeSingletonCreation  #创建之前,设置一个创建中的标识 ,这样就把beanName放入singletonsCurrentlyInCreation集合为空中了
		|--【ObjectFactory】#getObject 调用匿名内部类获取单例对象
			|--【AbstractAutowireCapableBeanFactory】#createBean  创建ben实例
				|--doCreateBean 完成Bean实例的创建(实例化、填充属性、初始化)
					|--createBeanInstance bean初始化第一步:默认调用无参构造实例Bean,构造参数依赖注入,就是发生在这一步
						|--instantiateBean 没有特殊处理的话,只需使用无参构造方法去创建Bean的实例
					|--boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));##解决循环依赖的关键步骤  是单列 允许循环引用 并且在singletonsCurrentlyInCreation集合中
					|--addSingletonFactory #earlySingletonExposure = true 将刚创建 提早暴露的bean放入三级缓存中
					|--populateBean  bean初始化第二步:填充属性(DI依赖注入发生在此步骤)调用反射和内省去进行属性设置,属性值需要进行类型转换
						|--applyPropertyValues 完成依赖注入
							|-- valueResolver.resolveValueIfNecessary #重要 重要 重要 判断传入的value的类型 返回bean实例 如果是RuntimeBeanReference 又去递归getBean去获取了
					|--initializeBean bean初始化第三步:调用初始化方法,完成bean的初始化操作(AOP发生在此步骤)
						|-- invokeInitMethods 执行初始化方法(先调用InitializingBean的afterPropertiesSet,再调用init-method属性指定的初始化方法)
							|--invokeCustomInitMethod 调用自定义初始化方法 执行init方法
	  	|--afterSingletonCreation  #创建成功之后,删除创建中的标识 将创建中的beanName从set集合singletonsCurrentlyInCreation中删除掉
		|--addSingleton 将产生的单例Bean放入缓存中(总共三级缓存)							

循环依赖问题

spring循环依赖问题

* 搞清楚什么是循环依赖
	** 依赖:引用、成员变量		
	** ClassA类---->ClassB类		ClassB类--->ClassA类
	** 依赖注入有两种注入方式:构造方法\setter方法注入			
	** 循环依赖其实就是循环引用,两个或两个以上的bean互相持有对方,最终形成闭环。			
			
* 循环依赖分为:
	* 构造方法
	* setter方法
			
	* 循环依赖的例子
		
    OrderService{
        UserService userService;

        saveOrder(){
            //插入订单表(需要用户名称,而页面只传递一个用户ID)
            //调用UserService去查询用户信息
        }
    }


    UserService{
        OrderService orderService;

        queryOrders(){
            //调用OrderService的服务
        }
    }
	#循环依赖会出现死循环

spring解决setter方法产生的循环依赖问题

#通过三级缓存来解决
** singletonObjects:第一级缓存
	***key是beanName
	***value是成品的Bean实例对象

** earlySingletonObjects:第二级缓存
	***key是beanName
	***value是半成品的Bean实例对象
				
** singletonFactories:第三级缓存
	***key是beanName
	***value是提早产生Bean实例的对象工厂ObjectFactory

举例如何解决循环依赖

* spring中Bean实例的完整创建流程
    ** Bean的实例化(new--------此处会反射调用构造器去new对象,所以说此处有可能会发生【构造器循环依赖】
    *** 此处产生的【构造器循环依赖】无法自动解决,只能修改依赖关系或者改为setter方法去依赖。
        OrderService{
            UserService userService;

            public OrderService(UserService userService){
                this.userService=userService;
            }
        }

        saveOrder(){
            //插入订单表(需要用户名称,而页面只传递一个用户ID)
            //调用UserService去查询用户信息
        }

    *** 注意:
        **** 此时从Java本身来说,Bean实例对象已经new 出来了,可以正常使用了。
        **** 但是从Spring来说,该Bean必须完成三个步骤(三个缓存步骤)之后,才认为可以被人正常使用。

    ** Bean的属性填充(setter)--------此处会对成员变量调用setter方法去进行依赖注入。----此处可能会发生【setter方法循环依赖】
        *** 其实此时Bean实例已经存在了,只是没有对外暴露使用而已。
        *** Spring的单例Bean被创建成功之后,会放入SingletonObjects的Map集合中,对外暴露使用。
        *** 可以使用缓存的方式去解决循环依赖问题。
	
	** #通过例子举例
		ClassA{
			ClassB
		}								
        ClassB{
            ClassA
        }
		*** 创建ClassA的流程
				1.ClassA实例化
					* 如果是单例bean,并且允许引用、该beanname存储到singletonsCurrentlyInCreation(Set集合),那么ClassA对象会提前被暴露给三级缓存保存。
				2.ClassA属性填充---给ClassB类型变量赋值(getBean)--->发现一级缓存中没有ClassB对象
					2.1 ClassB实例化 
						需要依赖注入ClassA,获取ClassA对象的引用,
					2.2 ClassB属性填充---ClassA类型变量赋值(getBean---去ioc容器中找)---
						* 此时去三级缓存中,可以找到该classA对应的ObjectFactory,通过该ObjectFactory获取代理对象获取原对象
						* 换句话说,此处已经找到bean了(只是这个bean还没有完成完成创建,但是bean对象的引用已经获取到了)
						* 如果此时还找不到ClassA,那么又会从第一步开始了,那这样就成死循环了。
							** 为了不让死循环,那么我们需要此时ClassA的实例被找到
							** SingletonObjects集合中不存放半成品,所以需要一个新的Map集合来存储半成品(第二级缓存????)
								*** 为了保证提前暴露的对象,和最终的对象是一个,我们需要在获取这个提前暴露的对象的时候,也需要判断是否进行提前代理
								*** 那么这个时候,我们就需要一个第三级缓存。(beanName,获取一个ObjectFactory的工厂类,该类就可以添加产生代理对象的逻辑)
								
							
						* 此时因为ClassA实例已经被new出来(提早暴露的循环引用)
					2.3 ClassB初始化
					2.4 ClassB实例放入SingletonObjects集合中(一级缓存)
				3.ClassA初始化
				4.ClassA实例放入SingletonObjects(存储的是代理对象或者原对象)集合中(才是对外暴露的引用集合)			
详细举例

​ 分析一下“A的某个field或者setter依赖了B的实例对象,同时B的某个field或者setter依赖了A的实例对象”这种循环依赖的情况。A首先完成了初始化的第一步,并且将自己提前曝光到singletonFactories中,此时进行初始化的第二步,发现自己依赖对象B,此时就尝试去get(B),发现B还没有被create,所以走create流程,B在初始化第一步的时候发现自己依赖了对象A,于是尝试get(A),尝试一级缓存singletonObjects(肯定没有,因为A还没初始化完全),尝试二级缓存earlySingletonObjects(也没有),尝试三级缓存singletonFactories,由于A通过ObjectFactory将自己提前曝光了,所以B能够通过ObjectFactory.getObject拿到A对象(虽然A还没有初始化完全,但是总比没有好呀),B拿到A对象后顺利完成了初始化阶段1、2、3,完全初始化之后将自己放入到一级缓存singletonObjects中。此时返回A中,A此时能拿到B的对象顺利完成自己的初始化阶段2、3,最终A也完成了初始化,进去了一级缓存singletonObjects中,而且更加幸运的是,由于B拿到了A的对象引用,所以B现在hold住的A对象完成了初始化。知道了这个原理时候,肯定就知道为啥Spring不能解决“A的构造方法中依赖了B的实例对象,同时B的构造方法中依赖了A的实例对象”这类问题了!因为加入singletonFactories三级缓存的前提是执行了构造器,所以构造器的循环依赖没法解决

三级缓存获取对象的顺序
* 先从一级缓存中查找
* 再从二级缓存中查找
* 最后没有则从三级缓存中获取
    ** ObjectFactory获取对象,有可能获取的是代理对象
    ** 将获取到的对象,【放入二级缓存】,同时删除此beanName对应的三级缓存数据
三级缓存添加对象的顺序
* 先将第一步new出来的对象,【添加到三级缓存】中的ObjectFactory里面保存。
* 三级缓存 和二级缓存是再过程中放入的。  最后放到一级缓存中 二 三级缓存就清空了
二级缓存的作用
A---B    B---C  C---A
A---C
* A依赖B 还依赖C A的引用里面有BC,提前创建BB创建中,还创建CB也会创建C,A还得使用C
* #为什么不能直接放入一级缓存?
	** 创建A的时候需要创建B,创建B的时候需要创建CC第一次被创建,走三级缓存,放入二级缓存,此处放入一级缓存不合适,C没有完整的创建成功。
	** A--C 需要创建C的时候 直接从二级缓存拿就行了
问题
** # 如果一个目标对象被aop动态加上事务增强功能(代理对象)的话,那么spring容器中存储的是目标对象,还是增强之后的对象,还是都存储?
	*** 答案是spring只会存储一个对象,如果目标对象被AOP产生了代理对象,那么存储的就是代理对象。
** # aop针对目标对象产生代理对象,是发生在bean创建的哪个流程呢?
	*** 是发生在Bean初始化的过程中,具体说,是发生在Bean调用初始化方法之后,去进行AOP流程。

AOP

解析阶段

【DefaultBeanDefinitionDocumentReader】#doRegisterBeanDefinitions 真正实现BeanDefinition解析和注册工作
	|--parseBeanDefinitions 委托给BeanDefinitionParserDelegate,从Document的根元素开始进行BeanDefinition的解析
		|--parseDefaultElement bean标签、import标签、alias标签,则使用默认解析规则
			|--processBeanDefinition 解析<Bean> 标签
				|--【BeanDefinitionParserDelegate】#parseBeanDefinitionElement  解析<bean>标签,获取BeanDefinition
					|--checkNameUniqueness   检查bean的id或者name是否唯一
					|--parseBeanDefinitionElement 解析<bean>标签,获取BeanDefinition对象
					|--new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray) 将BeanDefinition对象和BeanName封装到BeanDefinitionHolder对象中
				|--BeanDefinitionReaderUtils.registerBeanDefinition 注册最终的BeanDefinition到BeanDefinitionRegistry #以name为key,以BeanDefinition为Value,注册到Registry
		|--delegate.parseCustomElement 像context标签、aop标签、tx标签,则使用用户自定义的解析规则解析元素节点
			|--this.readerContext.getNamespaceHandlerResolver().resolve #根据不同的命名空间URI,去匹配不同的NamespaceHandler(一个命名空间对应一个NamespaceHandler);此处会调用DefaultNamespaceHandlerResolver类的resolve方法;两步操作:查找NamespaceHandler 、调用NamespaceHandler的init方法进行初始化(针对不同自定义标签注册相应的BeanDefinitionParser)
				|--【DefaultNamespaceHandlerResolver】#namespaceHandler.init() 调用NamespaceHandler类的init方法,初始化一些专门处理指定标签的BeanDefinitionParsers类  这里以AOP为例子
			|--【NamespaceHandlerSupport】#parse 调用匹配到的NamespaceHandler的解析方法;NamespaceHandler里面初始化了大量的BeanDefinitionParser来分别处理不同的自定义标签; 从指定的NamespaceHandler中,匹配到指定的BeanDefinitionParser
			|--return (parser != null ? parser.parse(element, parserContext) : null); 调用指定自定义标签的解析器,完成具体解析工作
				|--【ConfigBeanDefinitionParser】#parse
				|--configureAutoProxyCreator #向IoC容器中注册 AspectJAwareAdvisorAutoProxyCreator 类的BeanDefinition:(用于创建AOP代理对象的); BeanPostProcessor可以对实例化之后的bean进行一些操作;AspectJAwareAdvisorAutoProxyCreator 实现了BeanPostProcessor接口,可以对目标对象实例化之后,创建对应的代理对象
					|--【AopNamespaceUtils】#registerAspectJAutoProxyCreatorIfNecessary 注册AspectJAwareAdvisorAutoProxyCreator类的BeanDefinition
						|--AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary #向IoC容器中注册一个AspectJAwareAdvisorAutoProxyCreator 类的定义信息
				|--	parseAspect (1.解析<aop:aspect>标签 2.产生了很多BeanDefinition对象 3.aop:after等标签对应5个BeanDefinition对象 4.aop:after标签的method属性对应1个BeanDefinition对象 5.最终的AspectJPointcutAdvisor BeanDefinition类)
					|--parseAdvice  解析<aop:before>等五个子标签: 1.根据织入方式(before、after这些)创建RootBeanDefinition,名为adviceDef即advice定义 2.将上一步创建的RootBeanDefinition写入一个新的RootBeanDefinition,构造一个新的对象,名为advisorDefinition,即advisor定义 3.将advisorDefinition注册到DefaultListableBeanFactory中
						|--createAdviceDefinition  #通知增强类的BeanDefinition对象(核心)
						|--parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition) #将advisorDefinition注册到IoC容器中

执行阶段

【AbstractAutoProxyCreator】#postProcessAfterInitialization 负责创建代理对象的创建器
	|-- wrapIfNecessary(bean, beanName, cacheKey)  #使用动态代理技术,产生代理对象 bean : 目标对象 beanName :目标对象名称 cacheKey:就是beanName或者beanClass
		|--getAdvicesAndAdvisorsForBean 第一步:查找候选Advisor(增强器),第二步:针对目标对象获取合适的Advisor(增强器)
		|--createProxy 第三步: 通过jdk或者cglib动态代理,产生代理对象 针对目标对象产生代理对象
			|--evaluateProxyInterfaces #查看beanClass对应的类是否含有InitializingBean.class/DisposableBean.class/Aware.class接口,无则采用JDK动态代理,有则采用CGLib动态代理
			|--proxyFactory.getProxy 获取使用JDK动态代理或者cglib动态代理产生的对象

最终JDK动态代理对象会调用invoke方法
[JDKDynamicAopProxy]#invoke
	|--this.advised.getInterceptorsAndDynamicInterceptionAdvice 获取针对该目标对象的所有增强器(advisor),这些advisor都是有顺序的,他们会按照顺序进行链式调用
		|--this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice获取目标类中指定方法的MethodInterceptor集合,该集合是由Advisor转换而来
	|--new ReflectiveMethodInvocation #由它完成MethodInterceptor拦截到的方法是应该如何一个一个的执行,编写流水线执行流程,它将Advice封装成一个调用链
	|--invocation.proceed() #开始执行AOP的拦截过程 里边通过递归调用,先调用目标方法before方法,在调用目标方法,在调用after方法
		|-- ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
			|-- this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis()); #先通过反射执行执行before方法,执行之前先通过getBean 获取该方法的对象,在执行before方法
			|--return mi.proceed(); 执行目标方法
			|--最后在调用after方法	

相关概念

** Advice类:
	**** 五种通知
	**** 通知会调用自定义编写的【增强代码】
					
*** Advisor和Advice的关系
	* 一个Advisor(PointcutAdvisor)是封装了一个Advice(五种通知),同时还封装了对应的Pointcut对象(AspectJExpressionPointcut)
					
*** Advice和MethodInterceptor的关系是什么?
	* Advice接口是MethodInterceptor的父接口
	* Advice有五个实现类,也就是五种通知,但是只有三种通知是实现MethodInterceptor接口
        * AspectJAfterAdvice
        * AspectJAroundAdvice
        * AspectJAfterThrowingAdvice)
	* Advice另外的两个通知,要想和MethodInterceptor建立关系,需要使用适配器模式
        * AfterReturnningAdviceAdapter:【AspectJAfterReturnningAdvice----->MethodInterceptor】
        * MethodBeforeAdviceAdapter:【AspectJMethodBeforeAdviceAdvice----->MethodInterceptor】
		* ThrowsAdviceAdapter:【AspectJThrowsAdviceAdvice----->MethodInterceptor】----没有被用到

							
*** Advice为什么要封装成MethodInterceptor?
    * MethodInterceptor提供了一个接口功能叫intercept,使用此方法完成对执行方法的拦截,方便执行增强功能。
    * MethodInterceptor相当于针对五种通知有五个实现类,每个实现类都需要去完成方法拦截和【方法顺序的控制】。
					
*** 一个目标对象可以被多个增强功能去增强,最终只会产生一个代理对象。
    * 多个增强功能的执行顺序是如何保证的呢?
    * 【不同通知类型】的执行顺序是通过MethodInterceptor实现类去保证的。
    * 【同种通知类型】的执行顺序是通过对advice的加载顺序(xml顺序或者注解处理的顺序)去保证的。
* ReflectiveMethodInvocation的解析:
	* 由它完成MethodInterceptor拦截到的方法是应该如何一个一个的执行
    * 编写流水线执行流程
    * 它将Advice封装成一个调用链

springmvc

springmvc六大组件

在这里插入图片描述
springmvc 执行流程:

​ 1.客户端发送请求,首先到达DispatcherServlet (前端控制器),接收客户端请求,根据请求去查找对应的处理器

​ 2.找到处理器映射器HandlerMapping,提供了请求查找处理器的方式

​ 3.处理器映射器返回对应的处理器执行链

​ 4.根据处理器去查找对应的适配器,将类型不同意的Handler对象适配城统一的HandlerAdapter类型

​ 5.执行处理器,处理业务请求

​ 6.返回结果ModelAndView到处理器是配置

​ 7.返回结果到DispatcherServlet

​ 8.请求视图解析

​ 9.返回View对象

​ 10.视图渲染

​ 11.返回响应结果

  • DispatcherServlet 前端控制器

    接收请求、响应处理结果、分发请求、根据请求查找处理器、根据处理器查找适配器、根据查找到的适配器执行对应的处理器

  • HandlerMapping 处理器映射器

    ​ 提供了根据请求查找处理器的方式,处理器映射器有多种,每种实现类都通过不同的途径去获取处理器和请求的映射关系。

  • HandlerAdaper 处理器适配器

    ​ 根据找到的处理器,找到对应的处理器的适配器。

  • Handler 处理器

    ​ 处理业务请求

  • ViewResolver 势图解析器

    ​ 根据视图名称、解析出对应的View对象

  • View 视图

    ​ 将处理结果展示在页面上

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值