谢谢邀请仿笨狗漫画网源码!我将从以下几点介绍源码及Spring是怎样解析Bean定义并注册的
目录仿笨狗漫画网源码:
学习源码的重要性?
学习Spring源码需要基础吗仿笨狗漫画网源码?
怎样把Spring源码在本地运行仿笨狗漫画网源码?
Bean定义的加载过程
bean定义加载的流程图
总结
学习源码的重要性?(1) 可以提升技术功底仿笨狗漫画网源码,Spring源码也沉淀了很多年,有非常多的精华所在,不管我们什么水平,通过不断的阅读源码,能对我们的技术有很大的提升,并且工作中遇到类似问题的时候,可以借鉴源码中是怎么处理的。
(2) 深度的掌握技术框架:源码看多了,对于新的框架的学习和掌握都是很快的,看下框架的demo,就知道底层是怎么实现的。
比如,学习了Spring 中的AOP,就知道底层是用了JDK的动态代理。然后我们学习mybatis的时候,就在想Mybatis 为什么Service可以直接嗲用Dao接口,就可以直接查询数据库了呢 ?其实也是Spring底层对给接口做了动态代理。
(3) 对线上的问题可以进行快速的定位: 当生产上遇到问题时,能够快速的进行定位,这个能力可以快速秒杀别人。
(4) 对面试有很大的好处,特别是BAT大厂,一般都是问道源码级别的,你如果不会,可能第一轮就会被刷掉。
学习Spring源码需要基础吗?答案是肯定的,需要,那么需要哪些基础呢?
(1)Java 的技术功能
(2) 反射
(3) 设计模式: 简单工厂、工厂方法、单例模式、原型模式、代理模式、策略模式、模板方法模式、委派模式、适配器模式、装饰器模式、观察者模式
(4) Lambda表达式的知识
怎样把Spring源码在本地运行?(1) git clone ://github.com/spring-projects/spring-framework.git
(2) gradle下载,gradle需要JDK8版本
(3) 到下载的spring源码路径执行gradle命令,gradlew :spring-oxm:compileTestJava
(4) 用idea打开spring源码工程,在idea中安装插件kotlin,重启idea
(5) 把编译好的源码导入到工程中
Bean定义的加载过程
1、首先找到程序的入口
① 找到其构造方法:
② 调用 AnnotationConfigApplicationContext 构造方法,最终会调用父类 GenericApplicationContext的无参方法
③ 调用父类 AnnotationConfigApplicationContext 无参构造方法,生成bean定义读取器和Bean定义扫描器
上面方法的功能是: 实例化注解的Bean定义扫描器,定义类类路径下的bean定义扫描器
3.1 为Bean定义读取器赋值
3.1.1 为容器 中注册系统的Bean定义信息
上面代码主要是注册系统的Bean定义信息,包含以下几种:
① ConfigurationClassPostProcessor
是一个BeanFactory的后置处理器,主要功能是参与BeanFactory的构建,在这个类中,会解析@Configuration的配置类,解析@ComponentScan、@ComponentScans注解扫描的包,以及解析@Import等注解。
② AutowiredAnnotationBeanPostProcessor
AutowiredAnnotationBeanPostProcessor 实现了BeanPostProcessor,当Spring容器启动的时候,AutowiredAnnotationBeanPostProcessor 将扫描Spring容器中的所有Bean,当发现Bean中拥有
@Autowired 注解的时候就会找到与其匹配的Bean,并注入到对应的中去。
那么在什么时候调用的呢?我们可以看下debug堆栈;
③ RequiredAnnotationBeanPostProcessor
RequiredAnnotationBeanPostProcessor 是BeanPostProcessor实现.的,注释应用于bean属性的setter方法,它表明 受影响的bean 属性在配置时是否必须,如果配置了,没有此bean,则容器就会抛出一个BeanInitializationException 异常。
④ .CommonAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor 这个BeanPostProcessor 通过继承 InitDestroyAnnotationBeanPostProcessor 对 @PostConstruct 和 @PreDestroy注解的支持,以及对bean的依赖注入@Resource的支持。
⑤ EventListenerMethodProcessor
使用EventListenerMethodProcessor处理器来解析方法上的 @EventListener;
执行时机: 实在所有Bean都实例化以后执行的
④ 创建类路径下的bean定义扫描器
上述方法 是注册默认的扫描规则
⑤ 读取配置类
上述方法annotatedClasses为我们配置的mainConfig
annotatedClasses 就是MainConfig
此时上面主要解析 MainConfig,解析成BeanDefinition对象
上述的字段都是什么意思呢?
id: Bean的唯一标识名name: 用来为id 创建一个或者多个别名。class : 用来定义类的全限定名(包名 类名)parent: 子类bean定义它所引用它的父类的bean。abstract : 默认为false,用来定义bean是否为抽象bean,它表示这个Bean将不会被实例化,一般用于父类Bean,因为父类bean主要供子类bean继承使用。lazy-init: 用来定义这个bean是否实现懒初始化。如果为true,它将在BeanFactory启动时初始化所有的单例bean,反之,如果为false,它只在Bean请求使用时才开始创建SingletonBean。autowired : 自动装配,它定义了Bean 的自动装配方式。depends-on:依赖对象:这个Bean在初始化时依赖的对象,这个对象会在这个Bean初始化之前创建。init-method: 用来定义Bean的初始化方法,它会在Bean组装之后调用,它必须是一个无参的构造 方法。destroy-method: 用来定义Bean的销毁方法,它在BeanFactory关闭时调用。同样,它也必须是一个无参 的构造方法。只能适用于单例Bean.factory-method: 定义创建该Bean对象的 工厂方法。factory-bean:定义创建该 Bean对象的工厂类。
那么 BeanDefinitionHolder 又是什么意思呢?
BeanDefinitionHolder 只是封装了BeanDefinition对象,并且添加了beanName 和 alias 属性。
为什么这样设计呢?因为 我们定义bean时,可以定义多个别名的。
BeanDefinitionRegistry 又是什么呢?
BeanDefintion属性来看,我们并没有看到id 和 name属性没有体现在定义中,原因是ID其左右当前Bean的存储key注册到BeanDefinitionRegistry注册器中。name作为别名key注册到AliasRegistry注册中心。最后都是指向其对应的BeanDefinition。
2、AnnotatedBeanDefinitionReader(Bean定义读取)
BeanDefinition 中存储了Bean的信息,而BeanDefintiionRegistry是基于ID和name保存了Bean的定义。从Bean到BeanDefinition然后再注册到BeanDefintionRegistry整个过程。
从上图看出Bean的定义是由AnnotatedBeanDefinitionReader从@Bean的注解中构建出的,然后基于别名注册到BeanDefinitionRegistry。
BeanDefintionReader 的结构图如下:
2.1 bean定义的加载过程
(1) org.springframework.context.support.AbstractApplicationContext#refresh
注册Bean的 代码
invokeBeanFactoryPostProcessors(beanFactory);
(2) org.springframework.context.support.AbstractApplicationContext
#invokeBeanFactoryPostProcessors
然后实例化 容器初始化 的 ConfigurationClassPostProcessor Bean,然后调用其 的postProcessBeanDefinitionRegistry方法
BeanDefinitionRegistryPostProcessor 这个接口的调用分为三部分:
(1) 调用实现PriorityOrdered 排序接口
(2) 调用实现了Ordered排序接口
(3) 没有实现接口的调用
这个接口的理解如下: 获取BeanDefinition 对象,获取到这个对象就可以获取这个对象中注册的 所有BeanDefiniton对象,我们拥有这个对象后,我们就可以对里面所有的BeanDefinition 对象进行修改。
org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry 方法
最终调用 org.springframework.context.annotation.ConfigurationClassParser
最终调用 org.springframework.context.annotation.ConfigurationClassParser
#doProcessConfigurationClass 方法
下面方法主要功能如下:
解析 @PropretySource注解解析@ComponentScan注解解析@Import解析@ImportResource解析@Bean methods处理其他
bean定义加载的流程图
总结Spring 对注解的处理有两种方式:
1、直接将注解Bean注册到容器中
可以在初始化容器的时候注册,也可以在容器创建之后手动调用注册方法向容器中注册,然后通过手动刷新容器,使得容器对注册的注解Bean进行处理
2、通过扫描指定的 包及其子包下的所有类
在初始化注解容器的时指定要自动扫描的路径。如果容器创建以后,如果再向容器中添加注解Bean,则 需要手动调用容器扫描的方法,然后手动刷新容器,使得容器对所注册的Bean进行处理。
阅读:
哈士奇纯种的有什么特征
肩高:公犬53~60公分,母犬51~56公分;体重:公犬20~27公斤,母犬16~23公斤;颈部:中长,站立时直立并抬头挺胸,由肩部强而有力的耸立且有适度的颈拱。
狗的习性是什么
狗是食肉动物,容易和适宜消化肉食食品,进食时不大咀嚼。狗不能在行进中排便,喜啃咬,有自我防御能力能把毒食物吐出来。狗用唾液中水分蒸发来散热,狗在群居时有“等级制度”和主从关系,狗屁股和尾巴摸不得。
可蒙犬和波利犬的区别是什么
可蒙毛色以白色为主、奶白色,波利毛色以黑色为主、棕褐色。波利的体型比可蒙犬小,波利绳毛粗,下有细小的被毛,可蒙绳毛细,毛质硬。可蒙性格相对憨厚、沉稳,波利则活泼好动。
猎狐梗和雪纳瑞的区别是什么
猎狐梗性格机警刚烈,雪纳瑞友善活泼。猎狐梗比雪纳瑞脸更长,雪纳瑞毛比猎狐梗长很多。猎狐梗源于英国,雪纳瑞源于德国,不含英国血统。
狂犬病疫苗价格:狂犬病疫苗价格 打狂犬疫苗,要花多少钱?需要注意哪些问题?
谢谢邀请狂犬病疫苗价格!被猫狗等啮齿类动物咬伤后狂犬病疫苗价格,要尽早接种狂犬疫苗,一般在被咬伤后24小时内接种效果更好。不同品牌的狂犬疫苗价格不同狂犬病疫苗价格,以我中心的狂犬疫苗为例狂犬病疫苗价格,如果是二级暴露的话,只要单纯打狂犬疫苗,钱就会少点,一种是360元狂犬病疫苗价格,一种是420元,两种都是打五针,即被咬伤后的第0,3,7,14,28天各接种一针。如果是三级暴露,即伤口有流血,打完狂苗还要加打狂免,那样钱就多了,那就要看
淡水观赏龟的种类:最佳观赏淡水猪鼻龟如何饲养?
猪鼻子龟淡水观赏龟的种类,日常生活中需要注意什么呢? 猪鼻龟,特别是他的鼻子和猪鼻子一模一样,所以我们都叫它猪鼻子龟,猪鼻子龟外形可爱,游姿漂亮,是淡水乌龟中的最佳观赏类的乌龟 1 温度淡水观赏龟的种类,猪鼻子乌龟在适应温度应该保持28°左右合适,猪鼻子乌龟属于深水河龟,不需要晒台。 2环境,水质一定要保持清洁干净,水质不干净的话就会得水霉,龟皮掉落?开缸前必须注意用高锰酸钾或者是二氧化绿把鱼缸彻底的洗一遍淡水观赏龟的种类。超高透明
宠物火化归哪个部门管:火化场归哪个部门管 如果你养的宠物死了,你会给它火化吗?
我把我的小狗火化了,而且还装在骨灰坛里宠物火化归哪个部门管。过来北漂的时候,我还把骨灰坛一起带过来了。我打算死的时候找一个好地方,把自己放在那,然后再把小狗给我放在一起,我搬到哪,小狗都会跟我在一起,我们永远在一起,你们想看小狗骨灰坛吗?最后的那一张照片照片上的两个罐子就是了。我来北漂一共带了七只狗。五只是活的,两只是死的。我不知道我以后会嫁到哪里,可能嫁到哪里就跟老公放哪里。但是前提都是小狗也会跟我在一起。这七只狗以后可能就是七个小罐