1.Spring IoC:getBean 详解
2.什么是码分AOP、IOC他们的码分作用是什么?
3.Spring源码系列-BeanPostProcessor与BeanFactoryPostProcessor
4.Dubbo—SPI及自适应扩展原理
5.Spring源码- 02 Spring IoC容器启动之refresh方法
6.SpringIoc和Aop底层原理
Spring IoC:getBean 详解
接着 Spring IoC:finishBeanFactoryInitialization 详解,我们正式开始学习获取 bean 实例方法,码分该方法是码分 Spring 最核心的方法。
单击 preInstantiateSingletons 方法里的码分 getBean(beanName) 代码,进入该方法。码分游戏源码被盗
见 doGetBean 方法详解。码分
doGetBean
1.解析 beanName,码分主要是码分解析别名、去掉 FactoryBean 的码分修饰符 “&”,在 Spring IoC:finishBeanFactoryInitialization 详解 中的码分代码块4已解析过。
2.尝试从缓存中获取 beanName 对应的码分实例,在 Spring IoC:finishBeanFactoryInitialization 详解 中的码分代码块7已解析过。
3.1 返回 beanName 对应的码分实例对象(主要用于 FactoryBean 的特殊处理,普通 bean 会直接返回 sharedInstance 本身),码分见代码块1详解。
6.如果不是仅仅做类型检测,而是创建 bean 实例,这里要将 beanName 放到 alreadyCreated 缓存,见代码块5详解。
7.根据 beanName 重新获取 MergedBeanDefinition,在 Spring IoC:finishBeanFactoryInitialization 详解 中的代码块2已解析过。
8.2 检查 dep 是否依赖于 beanName,即检查是否存在循环依赖,见代码块6详解。
8.4 将 dep 和 beanName 的依赖关系注册到缓存中,见代码块7详解。
9.1 scope 为 singleton 的 bean 创建(新建了一个 ObjectFactory,并且重写了 getObject 方法),见代码块8详解。
9.1.1、9.2.2、9.3.4 创建 bean 实例,限于篇幅,在下篇文章单独解析。
9.1.2、9.2.4、9.3.6 返回 beanName 对应的实例对象,见代码块1详解。
9.2.1 scope 为 prototype 时创建实例前的操作、9.2.3 scope 为 prototype 时 创建实例后的操作,相对应的两个方法,见代码块详解。
代码块1:getObjectForBeanInstance
如果对 FactoryBean 不熟悉的,可以回头去看 Spring IoC:finishBeanFactoryInitialization 详解 中对 FactoryBean 的简单介绍。
6.mbd 为空,但是该 bean 的 BeanDefinition 在缓存中存在,则获取该 bean 的 MergedBeanDefinition,在 Spring IoC:finishBeanFactoryInitialization 详解 中的绩效管理系统 源码代码块2已经解析过。
8.从 FactoryBean 获取对象实例,见代码块2详解。
代码块2:getObjectFromFactoryBean
3.调用 FactoryBean 的 getObject 方法获取对象实例,见代码块3详解。
5.对 bean 实例进行后续处理,执行所有已注册的 BeanPostProcessor 的 postProcessAfterInitialization 方法,见代码块4详解。
代码块3:doGetObjectFromFactoryBean
很简单的方法,就是直接调用 FactoryBean 的 getObject 方法来获取到对象实例。
细心的同学可以发现,该方法是以 do 开头,看过 Spring IoC:源码总览 的同学知道,我在总览里就特别提到以 do 开头的方法是最终进行实际操作的方法,例如本方法就是 FactoryBean 最终实际进行创建 bean 对象实例的方法。
代码块4:postProcessObjectFromFactoryBean
这边走的是 AbstractAutowireCapableBeanFactory 里的方法。通过前面的介绍,我们知道创建的 BeanFactory 为 DefaultListableBeanFactory,而 DefaultListableBeanFactory 继承了 AbstractAutowireCapableBeanFactory,因此这边会走 AbstractAutowireCapableBeanFactory 的重写方法。
在 Spring IoC:registerBeanPostProcessors 详解 中已经学过 BeanPostProcessor,在创建完 bean 实例后,会执行 BeanPostProcessor 的 postProcessAfterInitialization 方法。
代码块5:markBeanAsCreated
2.这边会将 beanName 对应的 MergedBeanDefinition 移除,然后在之后的代码重新获取,主要是为了使用最新的 MergedBeanDefinition 来进行创建操作。
代码块6:isDependent
这边引入了一个缓存 dependentBeanMap:beanName -> 所有依赖 beanName 对应的 bean 的 beanName 集合。内容比较简单,就是检查依赖 beanName 的集合中是否包含 dependentBeanName,隔层依赖也算。例如:A 依赖了 B,B 依赖了 C,则 A 也算依赖了 C。
代码块7:registerDependentBean
这边又引入了一个跟 dependentBeanMap 类似的缓存,dependenciesForBeanMap:beanName -> beanName 对应的 bean 依赖的所有 bean 的 beanName 集合。
这两个缓存很容易搞混,举个简单例子:例如 B 依赖了 A,则 dependentBeanMap 缓存中应该存放一对映射:其中 key 为 A,value 为含有 B 的 Set;而 dependenciesForBeanMap 缓存中也应该存放一对映射:其中 key 为:B,value 为含有 A 的 Set。
代码块8:getSingleton
5.创建单例前的操作,7.创建单例后的操作,这两个方法是对应的,见代码块9详解。
6.执行 singletonFactory 的 getObject 方法获取 bean 实例,该方法会走文章开头 doGetBean 方法的注释 9.1.1。
8.如果是新的单例对象,将 beanName 和对应的单例对象添加到缓存中,见代码块详解。寿光商铺网源码
代码块9:beforeSingletonCreation、afterSingletonCreation
inCreationCheckExclusions 是要在创建检查排除掉的 beanName 集合,正常为空,可以不管。这边主要是引入了 singletonsCurrentlyInCreation 缓存:当前正在创建的 bean 的 beanName 集合。在 beforeSingletonCreation 方法中,通过添加 beanName 到该缓存,可以预防出现构造器循环依赖的情况。
为什么无法解决构造器循环依赖?
我们之前在 Spring IoC:finishBeanFactoryInitialization 详解 中的代码块7提过,getSingleton 方法是解决循环引用的核心代码。解决逻辑的第一句话:“我们先用构造函数创建一个 “不完整” 的 bean 实例”,从这句话可以看出,构造器循环依赖是无法解决的,因为当构造器出现循环依赖,我们连 “不完整” 的 bean 实例都构建不出来。Spring 能解决的循环依赖有:通过 setter 注入的循环依赖、通过属性注入的循环依赖。
代码块:addSingleton
代码块:beforePrototypeCreation、afterPrototypeCreation
该方法和代码块9的两个方法类似。主要是在进行 bean 实例的创建前,将 beanName 添加到 prototypesCurrentlyInCreation 缓存;bean 实例创建后,将 beanName 从 prototypesCurrentlyInCreation 缓存中移除。这边 prototypesCurrentlyInCreation 存放的类型为 Object,在只有一个 beanName 的时候,直接存该 beanName,也就是 String 类型;当有多个 beanName 时,转成 Set 来存放。
总结
本文介绍了获取 bean 实例的大部分内容,包括先从缓存中检查、 FactoryBean 的 bean 创建、实例化自己的依赖(depend-on 属性)、创建 bean 实例的前后一些标记等,在下篇文章中,将解析创建 bean 的内容。
推荐阅读
什么是AOP、IOC他们的作用是什么?
什么是IoC
Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。如何理解好Ioc呢?理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”,那我们来深入分析一下:
控制是什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,项目融资网站源码是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。
为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。
IoC能做什么
IoC不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。
其实IoC对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化。应用程序原本是老大,要获取什么资源都是主动出击,但是在IoC/DI思想中,应用程序就变成被动的了,被动的等待IoC容器来创建并注入它所需要的资源了。
IoC和DI
DI—Dependency Injection,即“依赖注入”:是组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
注:如果想要更加深入的了解IoC和DI,请参考大师级人物Martin Fowler的一篇经典文章《Inversion of Control Containers and the Dependency Injection pattern》,原文地址:/articles/injection.html。
AOP:面向切面编程
什么是android 短信系统源码AOP:
概念:在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。(百度百科)
简单的说:就是将程序中重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。
AOP的作用和优势:
作用:从定义中来看,就是为了在程序运行期间,不修改源码对已有方法进行增强。
优势:减少重复代码 提交了开发效率 维护方便
实现方式: 就是动态代理的技术
具体的作用:实现事务的控制 日志 和 安全模块
想系统的学习编程可以来我这看看,希望对您有所帮助!~
Spring源码系列-BeanPostProcessor与BeanFactoryPostProcessor
在Spring框架中,BeanPostProcessor与BeanFactoryPostProcessor各自承担着不同的职责,它们在IoC容器的工作流程中起着关键作用。
BeanFactoryPostProcessor作用于BeanDefinition阶段,对容器中Bean的定义进行处理。这个过程发生在BeanFactory初始化时,对BeanDefinition进行修改或增强,提供了一种在不修改源代码的情况下定制Bean的机制。相比之下,BeanPostProcessor则在Bean实例化之后生效,对已经创建的Bean对象进行进一步处理或替换,提供了更晚、更灵活的扩展点。
以制造杯子为例,BeanFactoryPostProcessor相当于在选择材料和形状阶段进行定制,而BeanPostProcessor则在杯子制造完成后,进行诸如加花纹、抛光等深加工。
在Spring框架中,BeanPostProcessor的使用场景较为广泛,尤其在实现AOP(面向切面编程)时,通过使用代理类替换原始Bean,实现如日志记录、事务管理等功能。
此外,容器在启动后,还会进行消息源初始化、广播器初始化及监听器初始化,为Bean实例化做好准备。完成这些准备工作后,容器会调用registerBeanPostProcessors方法注册BeanPostProcessor,对已创建的Bean进行进一步处理。同时,初始化消息源、广播器和监听器,为后续事件处理做好基础。
总结,BeanFactoryPostProcessor与BeanPostProcessor在Spring IoC容器中的作用各有侧重。前者侧重于对BeanDefinition的定制,后者则是在Bean实例化后的进一步加工,两者共同为构建灵活、可扩展的IoC容器提供了强大的支持。
在深入分析Spring框架的源码时,我们发现refresh()方法的实现中包含了对BeanFactoryPostProcessor和BeanPostProcessor的注册与处理。这些处理步骤确保了容器能够在启动时对Bean进行正确的配置和初始化。
文章中通过一个例子展示了如何使用BeanFactoryPostProcessor替换已注册Bean的实现,以及对其源码的分析。通过例子和源码的结合,读者能够更直观地理解这些后置处理器在Spring框架中的应用和工作原理。
Dubbo—SPI及自适应扩展原理
引言:Dubbo作为一个广泛应用于国内的RPC框架,其设计思想极具学习价值。本文基于Dubbo2.5.3版本源码,深入探讨SPI(Service Provider Interface)及自适应扩展原理,解析Dubbo的高扩展性实现基础。
一、SPI(Service Provider Interface)简介:SPI是一种服务发现机制,旨在解耦接口与具体实现,允许第三方组件无缝集成至应用中。举例说明,Java内置SPI机制,如数据库驱动实现,通过Driver接口统一,各数据库厂商自定义驱动类即可实现连接不同数据库,无需修改代码。
二、Java SPI与Dubbo SPI对比:Dubbo基于Java SPI思想,提供更强大扩展能力。配置文件以接口全类名命名,内容非Java SPI标准形式。下面以Protocol扩展为例解析。
三、Dubbo SPI实现细节:核心类ExtensionLoader负责SPI管理。构造方法初始化loader,通过类名获取扩展类实例。关键点在于getExtension方法,内部实现从缓存获取或创建并缓存扩展类实例。loadExtensionClasses方法负责加载配置文件,解析实现类信息。
四、自适应扩展机制解析:Dubbo中存在大量扩展类,自适应机制确保按需加载。@Adaptive注解用于标识可动态加载的扩展类。构造方法中获取适配类,通过反射实例化。自适应类通过反射调用扩展类方法,实现懒加载功能。
五、Dubbo IOC解析:injectExtension方法实现依赖注入,通过反射和setter方法注入扩展实例。AdaptiveExtensionFactory适配类负责缓存所有ExtensionFactory,确保按需加载。本文详细解析Dubbo依赖注入实现原理。
六、总结:通过源码分析,可深入了解Dubbo扩展机制、设计模式应用以及如何实现优雅的扩展开发。未来在实际项目中,可灵活应用所学知识进行自定义扩展,甚至重构已有项目。反思当前项目,是否能利用今日所学进行优化和改进。
Spring源码- Spring IoC容器启动之refresh方法
在注册阶段,AnnotationConfigApplicationContext构造方法中的第一个方法被分析过。接下来,我们关注第二个方法:register(componentClasses)。在使用XML配置方式时,通过new ClassPathXmlApplicationContext("classpath:spring.xml")来创建实例,其中需要指定xml配置文件路径。使用注解方式时,也需要为ApplicationContext提供起始配置源头,这里使用配置类代替xml配置文件,按照配置类中的注解(如@ComponentScan、@Import、@Bean)解析并注入Bean到IoC容器。
通过配置类,Spring解析注解实现Bean的注入。使用@Configuration注解定义的配置类相当于xml配置文件,但目前Spring推荐使用注解方式,xml配置的使用概率正在降低。
register(componentClasses)方法的核心逻辑在AnnotatedBeanDefinitionReader#doRegisterBean中,将传入的配置类解析为BeanDefinition并注册到IoC容器。ConfigurationClassPostProcessor这个BeanFactory后置处理器在IoC初始化时,获取配置类的BeanDefinition集合,开始解析。
真正启动IoC容器的流程在refresh()方法中,这是了解IoC容器启动流程的关键步骤。refresh方法在AbstractApplicationContext中定义,采用模板模式,提供IoC初始化流程的基本实现,子类可以扩展。
下面分析refresh()方法的每个步骤,以了解IoC容器的启动流程。
prepareRefresh方法主要在refresh执行前进行准备工作,如设置Context的启动时间、状态,以及扩展系统属性相关。
initPropertySources()方法主要用于扩展配置来源,如网络、物理文件、数据库等加载配置信息。StandardEnvironment默认只提供加载系统变量和应用变量的功能,用于子类扩展。
❝initPropertySources方法常见扩展场景包括:❞
getEnvironment().validateRequiredProperties()确保设置的必要属性在环境中存在,否则抛出异常终止应用。
BeanFactory是Spring的基本IoC容器,ApplicationContext包装了BeanFactory,提供更智能、更便捷的功能。ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();获取的BeanFactory是IoC容器初始化工作的基础。
上面获取的BeanFactory还不能直接使用,需要填充必要的配置信息。至此,IoC容器的启动流程基本完成。
这里对IoC启动流程有个大致、直观的印象。主要步骤包括:准备阶段、配置来源扩展、初始化BeanFactory、填充配置、解析配置类、注册Bean、实例化BeanPostProcessor、初始化国际化和事件机制、以及创建内嵌Servlet容器(在SpringBoot中实现)。这些步骤确保了IoC容器顺利启动并管理Bean。
SpringIoc和Aop底层原理
文章内容
本文深入解析Spring框架中的Ioc和Aop底层原理。
首先,Ioc(依赖注入)通过Spring配置文件实现对象的创建,而不是传统的new方式。实现Ioc,主要有两种方法:配置文件和注解。Ioc底层原理包括:使用xml配置文件创建类,通过dom4j解析配置,工厂设计模式配合使用,以及反射技术。通过Ioc,开发者只需修改bean配置属性,就能更换UserService类,有效降低类间的耦合度。
与DI(依赖注入)相比,Ioc更加关注控制反转,将对象创建权交由Spring管理;而DI则着重于在对象内部注入属性值。Ioc与DI相辅相成,DI必须在Ioc的基础上进行操作,即先创建对象后进行属性注入。
文章接下来解释了Spring整合web项目原理,包括加载Spring核心配置文件、服务器启动时动态加载配置和创建对象,以及使用ServletContext和监听器实现这一过程。具体操作包括为每个项目创建ServletContext对象、监听对象创建事件,并在contextInitialized()方法中加载配置文件和创建对象,最后将对象存储在ServletContext域对象中以便于获取。
Aop(面向切面编程)在Spring中实现,通过动态代理扩展功能,无需修改源代码。动态代理分为两种情况:有接口时使用jdk动态代理,无接口时使用cglib动态代理。Aop提供多种增强类型,包括前置、后置、异常、最终和环绕增强。
文章最后建议读者关注学习资源,通过扫描二维码获取更多知识和学习资料。
如何快速读懂项目源码javaWeb
一:学会如何读一个JavaWeb项目源代码 步骤:表结构->web.xml->mvc->db->spring
ioc->log-> 代码
1、先了解项目数据库的表结构,这个方面是最容易忘记 的,有时候我们只顾着看每一个方法是怎么进行的,却没
有去了解数据库之间的主外键关联。其实如果先了解数据 库表结构,再去看一个方法的实现会更加容易。
2、然后需要过一遍web.xml,知道项目中用到了什么拦
截器,监听器,过滤器,拥有哪些配置文件。如果是拦截 器,一般负责过滤请求,进行AOP 等;如果是监 可能是定时任务,初始化任务;配置文件有如使用了 spring
后的读取mvc 相关,db 相关,service 相关,aop 相关的文件。
3、查看拦截器,监听器代码,知道拦截了什么请求,这
个类完成了怎样的工作。有的人就是因为缺少了这一步, 自己写了一个action,配置文件也没有写错,但是却怎么
调试也无法进入这个action,直到别人告诉他,请求被拦
4、接下来,看配置文件,首先一定是mvc相关的,如 springmvc
中,要请求哪些请求是静态资源,使用了哪些 view 策略,controller 注解放在哪个包下等。 然后是db 相关配置文件,看使用了什么数据库,使用了
什么orm框架,是否开启了二级缓存,使用哪种产品作 为二级缓存,事务管理的处理,需要扫描的实体类放在什 么位置。最后是spring 核心的ioc
功能相关的配置文件, 知道接口与具体类的注入大致是怎样的。当然还有一些如 apectj 置文件,也是在这个步骤中完成
5、log
相关文件,日志的各个级别是如何处理的,在哪些 地方使用了log 记录日志
6、从上面几点后知道了整个开源项目的整体框架,阅读 每个方法就不再那么难了。
7、当然如果有项目配套的开发文档也是要阅读的。