1.【Spring源码】7.如何添加自定义的码分BeanFactoryPostProcessor
2.Spring源码系列-BeanPostProcessor与BeanFactoryPostProcessor
3.Spring容器之refresh方法源码分析
4.学习编程|Spring源码深度解析 读书笔记 第4章:bean的加载
5.Spring容器刷新—02—obtainFreshBeanFactory
6.25. Spring源码篇之SpEL表达式
【Spring源码】7.如何添加自定义的BeanFactoryPostProcessor
关于BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor的父子关系鉴定:
由图示可知,BeanDefinitionRegistryPostProcessor是码分BeanFactoryPostProcessor的子类。
实现步骤包括新建类并实现接口,码分通过配置文件或自定义函数让Spring识别。码分
实现方式一:在配置文件中定义,码分启动类添加代码,码分光猫源码输出结果验证。码分
实现方式二:重写ClassPathXmlApplicationContext的码分customizeBeanFactory函数,新建MyApplicationContext类,码分修改启动类,码分再次验证。码分
两种方法区别在于,码分方式二虽能成功执行新建类,码分但spring上下文对象的码分BeanDefinitionNames和BeanDefinitionMap不包含这些类。
使用Debug方式进一步确认,码分方式一能将新建类添加到Spring上下文,而方式二则不会。
总结:通过配置文件让Spring识别更为有效,能将自定义的BeanFactoryPostProcessor类添加到Spring上下文的BeanDefinitionMap和BeanDefinitionNames集合中。
Spring源码系列-BeanPostProcessor与BeanFactoryPostProcessor
在Spring框架中,BeanPostProcessor与BeanFactoryPostProcessor各自承担着不同的职责,它们在IoC容器的工作流程中起着关键作用。
BeanFactoryPostProcessor作用于BeanDefinition阶段,对容器中Bean的定义进行处理。这个过程发生在BeanFactory初始化时,对BeanDefinition进行修改或增强,提供了一种在不修改源代码的情况下定制Bean的机制。相比之下,BeanPostProcessor则在Bean实例化之后生效,对已经创建的Bean对象进行进一步处理或替换,提供了更晚、更灵活的扩展点。
以制造杯子为例,qq在线挂机源码BeanFactoryPostProcessor相当于在选择材料和形状阶段进行定制,而BeanPostProcessor则在杯子制造完成后,进行诸如加花纹、抛光等深加工。
在Spring框架中,BeanPostProcessor的使用场景较为广泛,尤其在实现AOP(面向切面编程)时,通过使用代理类替换原始Bean,实现如日志记录、事务管理等功能。
此外,容器在启动后,还会进行消息源初始化、广播器初始化及监听器初始化,为Bean实例化做好准备。完成这些准备工作后,容器会调用registerBeanPostProcessors方法注册BeanPostProcessor,对已创建的Bean进行进一步处理。同时,初始化消息源、广播器和监听器,为后续事件处理做好基础。
总结,BeanFactoryPostProcessor与BeanPostProcessor在Spring IoC容器中的作用各有侧重。前者侧重于对BeanDefinition的定制,后者则是在Bean实例化后的进一步加工,两者共同为构建灵活、可扩展的IoC容器提供了强大的支持。
在深入分析Spring框架的源码时,我们发现refresh()方法的实现中包含了对BeanFactoryPostProcessor和BeanPostProcessor的注册与处理。这些处理步骤确保了容器能够在启动时对Bean进行正确的配置和初始化。
文章中通过一个例子展示了如何使用BeanFactoryPostProcessor替换已注册Bean的uu农场源码实现,以及对其源码的分析。通过例子和源码的结合,读者能够更直观地理解这些后置处理器在Spring框架中的应用和工作原理。
Spring容器之refresh方法源码分析
Spring容器的核心接口BeanFactory与ApplicationContext之间的关系是继承,ApplicationContext扩展了BeanFactory的功能,提供了初始化环境、参数、后处理器、事件处理以及单例bean初始化等更全面的服务,其中refresh方法是Spring应用启动的入口点,负责整个上下文的准备工作。 让我们深入分析AbstractApplicationContext#refresh方法在启动过程中的具体操作:准备刷新阶段: 包括系统属性和环境变量的检查和准备。
获取新的BeanFactory: 初始化并解析XML配置文件。
customizeBeanFactory: 个性化BeanFactory设置,如覆盖定义、处理循环依赖等。
loadBeanDefinitions: 通过解析XML文件,创建BeanDefinition对象并注入到容器中。
填充BeanFactory功能: 设置classLoader、表达式语言处理器,增强Aware接口处理,添加AspectJ支持和默认系统环境bean等。
激活BeanFactory后处理器: 分为BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor,分别进行BeanDefinition注册和BeanFactory增强。
注册BeanPostProcessors: 拦截Bean创建的后处理器,按优先级注册。
初始化其他组件: 包括MessageSource、ApplicationEventMulticaster和监听器。
初始化非惰性单例: 预先实例化这些对象。
刷新完成: 通知生命周期处理器并触发ContextRefreshedEvent。
以上是refresh方法在Spring应用启动流程中的关键步骤。以上内容仅为个人理解,无限分类网站源码如需更多信息,可参考CSDN博客链接。学习编程|Spring源码深度解析 读书笔记 第4章:bean的加载
在Spring框架中,bean的加载过程是一个精细且有序的过程。首先,当需要加载bean时,Spring会尝试通过转换beanName来识别目标对象,可能涉及到别名或FactoryBean的识别。
加载过程分为几步:从缓存查找单例,Spring容器内单例只创建一次,若缓存中无数据,会尝试从singletonFactories寻找。接着是bean的实例化,从缓存获取原始状态后,可能需要进一步处理以符合预期状态。
原型模式的依赖检查是单例模式特有的,用来避免循环依赖问题。然后,如果缓存中无数据,会检查parentBeanFactory,递归加载配置。BeanDefinition会被转换为RootBeanDefinition,合并父类属性,确保依赖的正确初始化。
Spring根据不同的scope策略创建bean,如singleton、prototype等。类型转换是后续步骤,可能将返回的bean转换为所需的类型。FactoryBean的使用提供了灵活的实例化逻辑,用户自定义创建bean的过程。
当bean为FactoryBean时,tdoa定位算法源码getBean()方法代理了FactoryBean的getObject(),允许通过不同的方式配置bean。缓存中获取单例时,会执行循环依赖检测和性能优化。最后,通过ObjectFactory实例singletonFactory定义bean的完整加载逻辑,包括回调方法用于处理单例创建前后的状态。
Spring容器刷新——obtainFreshBeanFactory
本文讨论的是Spring容器中的刷新过程,重点讲解了创建BeanFactory实例的操作。BeanFactory和ApplicationContext在Spring源码中有多种实现,ApplicationContext在BeanFactory基础上增加了额外功能,如管理应用上下文、提供更丰富的依赖注入等。
在实际应用中,选择使用哪个具体实现取决于项目的特定需求。本文列出了两种常见的实现:AbstractApplicationContext和GenericApplicationContext。
AbstractApplicationContext支持多次刷新,内部维护了一个volatile的DefaultListableBeanFactory实例。刷新逻辑分为两步:首先调用refreshBeanFactory()方法,然后返回此实例通过getBeanFactory()方法。
GenericApplicationContext的实现相对简单,对于obtainFreshBeanFactory()方法的调用几乎不做任何操作。
至于应用程序中使用哪个具体的BeanFactory实现,这取决于项目的配置和需求。在传统的Servlet环境下,通常通过ContextLoaderListener加载上下文,而SpringBoot环境中的ApplicationContext创建则通过ApplicationContextFactory完成。
具体实现细节和流程在不同环境下的差异,如Servlet环境中的ContextLoaderListener和ContextLoader的使用,以及SpringBoot环境中的ApplicationContextFactory的实现,将在后续的文章中进行详细阐述。
. Spring源码篇之SpEL表达式
Spring的SpEL表达式,即Spring Expression Language,是Spring框架中实现复杂功能的关键组件。在Spring中,独立的spring-expression模块用于支持这一功能。本文将提供对SpEL表达式源码的简要分析,以帮助理解其基本用法。 在AbstractBeanFactory中,有一个名为beanExpressionResolver的属性,用于配置默认的表达式解析器。在初始化BeanFactory时,通过AbstractApplicationContext#prepareBeanFactory设置默认值,该值默认为开启状态,可通过配置参数spring.spel.ignore=false来关闭表达式功能。 核心解析组件是BeanExpressionResolver,它提供了evaluate方法,用于解析传入的表达式并返回结果。作为实现类,StandardBeanExpressionResolver具体实现evaluate方法,执行解析任务。 解析SpEL表达式的接口是ExpressionParser,它接收表达式和ParserContext,后者定义了解析规则。关键子类包括SpelExpressionParser、InternalSpelExpressionParser和TemplateAwareExpressionParser。在解析过程中,会调用TemplateAwareExpressionParser#parseExpressions方法,该方法进一步调用InternalSpelExpressionParser#doParseExpression,实现表达式的详细解析。解析流程的关键步骤是tokenizer.process和eatExpression方法,它们负责识别和处理特殊字符以及逻辑运算。 SpEL表达式本质上是一个语法树结构,涉及复杂的运算、对象访问和方法调用。它支持的字符规范包括括号、逻辑运算符(如or、and)、比较运算符(如>、<)、点号(用于访问对象属性)、问号(用于条件判断)、美元符号(用于访问变量)等。 以下是使用SpEL表达式的简单示例:案例一
输出特定值或表达式的结果。案例二
对数据集进行处理,例如筛选、排序或计算。案例三
执行对象方法,如调用实例方法或访问静态方法。案例四
使用SpEL获取Spring容器中的Bean实例,包括使用@和&注解来分别获取普通Bean和FactoryBean。 通过以上分析,我们大致了解了SpEL表达式的功能和基本用法。理解这些关键类及其功能有助于在实际开发中灵活运用SpEL,提高代码的可维护性和可读性。尽管SpEL的实现细节复杂,掌握其核心概念和用法足以应对常见的应用场景。Spring扩展点探索之BeanFactoryPostProcessor
Spring的BeanFactoryPostProcessor是一种强大的工具,它允许在Bean实例化前对Bean的属性进行后置处理。想象一下,如果你的Bean中存在占位符,BeanFactoryPostProcessor就像一个预处理器,负责在配置参数填充这些占位符,确保Bean在初始化时得到正确的值。
这个接口仅需实现一个postProcessBeanFactory()方法,通过它,开发者可以根据需要定制Bean的属性。例如,创建一个User类,配置类将其注册到Spring容器,然后自定义一个MyBeanFactoryPostProcessor,重写postProcessBeanFactory()方法,用于修改User的属性,如将userName从Jack改为Tom。
当你在测试类中获取并打印User对象时,可以看到属性已经被修改为Tom。这显示了BeanFactoryPostProcessor如何在初始化阶段灵活地改变Bean的行为。Spring通过refresh()方法中的invokeBeanFactoryPostProcessors()函数,自动调用每个注册的BeanFactoryPostProcessor,实现了这个过程的自动化。
源码分析揭示,Spring内部通过遍历BeanFactoryPostProcessor列表并调用postProcessBeanFactory(),确保在Bean实例化之前,所有定制的处理逻辑得以执行。因此,BeanFactoryPostProcessor是Spring框架中实现Bean属性动态修改的关键环节。
@Lazy注解源码分析
@Lazy注解是Spring框架3.0版本后引入的,用于控制bean的懒加载行为,主要用途是延迟依赖注入的初始化。默认情况下,当ApplicationContext启动和刷新时,所有的单例bean会被立即初始化。然而,有时可能希望某些bean在首次使用时才被初始化。实现这一目标的方法是将@Lazy注解应用到bean或注入点,如@Autowired,以创建懒解析代理,从而实现延迟注入。
@Lazy注解对@Bean、@Component或@Bean定义的bean的延迟初始化特别有用。当用在@Configuration类上时,它会影响该配置中的所有@Bean定义。通过在启动类入口使用AnnotationConfigApplicationContext并提供MyConfiguration组件类,从MyService bean获取并调用其show方法,可以观察到MyBean在首次被请求时才被初始化,而MyService的初始化则立即进行。MyBean类的构造函数在被调用时打印"MyBean的构造函数被调用了!",show方法则打印"hello world!"。MyService类通过@Autowired注入MyBean,由于在注入点上添加了@Lazy注解,myBean的实际注入被延迟,直到首次尝试访问它时。
源码分析表明,在启动类构造函数中,执行了三个步骤以初始化实例。在refresh方法中,重点关注了finishBeanFactoryInitialization方法,该方法会对所有剩余非懒加载的单例bean对象进行初始化,除非它们显式标记为懒加载。在preInstantiateSingletons方法中,确保所有非懒加载的单例bean在容器启动时被初始化,除非它们被标记为懒加载。这使得@Lazy注解对于希望推迟bean初始化的场景非常有用。
在getBean()方法中,通过doGetBean方法执行了创建bean的过程。在doCreateBean方法中,对bean的属性进行注入。在populateBean方法中,如果一个属性被标记为@Autowired,并且与@Lazy结合使用,那么实际的懒加载逻辑会在其他部分处理,特别是通过AutowiredAnnotationBeanPostProcessor。在resolveFieldValue方法中,解析@Autowired字段的值,并确定应为目标字段注入哪个bean。在resolveDependency方法中,如果依赖关系标记为懒加载,它将返回一个懒加载代理,只有在应用程序真正访问该依赖时,实际的bean才会被初始化。
总结而言,@Lazy注解提供了在Spring容器中控制bean初始化的灵活性,允许开发者根据需要延迟依赖注入的初始化,从而优化应用性能和资源管理。在实践过程中,注意合理使用@Lazy注解,确保代码的清晰性和可维护性。同时,理解Spring容器在bean初始化过程中的工作原理,可以帮助开发者更有效地利用该框架的特性,实现更高效的应用开发。