返回顶部
首页 > 资讯 > 精选 >spring bean的自动注入及循环依赖问题怎么解决
  • 107
分享到

spring bean的自动注入及循环依赖问题怎么解决

2023-07-05 15:07:46 107人浏览 泡泡鱼
摘要

这篇文章主要介绍了spring bean的自动注入及循环依赖问题怎么解决的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇spring bean的自动注入及循环依赖问题怎么解决文章都会有所收获,下面我们一起来看看吧

这篇文章主要介绍了spring bean的自动注入及循环依赖问题怎么解决的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇spring bean的自动注入及循环依赖问题怎么解决文章都会有所收获,下面我们一起来看看吧。

一、spring中的各种注入方式

我们对Bean的注入,一般有下面几种方式:

1)、通过@Autowired、@Resource作用在属性上

2)、通过@Autowired、@Resource作用在方法上

3)、通过提供set方法+改变注入模型为自动注入

4)、通过BeanDefinition方式完成属性注入

我们先说前三种方式:

我们用下面的测试类来检验:

测试注解作用在属性上:

@Componentpublic class AnnotationAutowiredFiledBeanTest {}

测试注解作用在方法上:

@Componentpublic class AnnotationAutowiredMethodBeanTest {}

测试通过提供set方法+改变注入模型为自动注入

@Componentpublic class AutowiredInjectByTypeMethodBeanTest {}

修改为注入模型类:

@Componentpublic class UpdateBeanInfoBeanFactoryPostProcessor implements BeanFactoryPostProcessor{@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {AbstractBeanDefinition a = (AbstractBeanDefinition) beanFactory.getBeanDefinition("a");a.setAutowireMode(2);//a.getPropertyValues().add("beanDefinitionPropertyValuesBeanTest",new BeanDefinitionPropertyValuesBeanTest());}}

各种方式的注入类:

@Component("a")public class SpringBeanInfoTest { //@Autowired作用在属性上进行注入@AutowiredAnnotationAutowiredFiledBeanTest autowiredFiledBeanTest; //@Autowired作用在方法上进行注入@Autowiredpublic void setAnnotationAutowiredMethodBeanTest(AnnotationAutowiredMethodBeanTest annotationAutowiredMethodBeanTest){System.out.println("AnnotationAutowiredMethodBeanTest=[{}]"+annotationAutowiredMethodBeanTest);} //使用自动注入(使用byType的模式)public void setAutowiredInjectByTypeMethodBeanTest(AutowiredInjectByTypeMethodBeanTest autowiredInjectByTypeMethodBeanTest){System.out.println("AutowiredInjectByTypeMethodBeanTest=[{}]"+autowiredInjectByTypeMethodBeanTest);}    //用来打印@Autowired作用在属性上进行注入是否成功public void printf(){System.out.println("autowiredFiledBeanTest=[{}]"+autowiredFiledBeanTest);} }

启动测试类:

配置类:

@Configuration@ComponentScan("com.spring.demo.introspect")public class App { }

启动类:

public class ApplicationTest {  @Testpublic void testSpringInject() throws NoSuchFieldException, IntrospectionException {AnnotationConfigApplicationContext context= new AnnotationConfigApplicationContext();context.reGISter(App.class);context.refresh();context.getBean(SpringBeanInfoTest.class).printf();    }}

此时我们在UpdateBeanInfoBeanFactoryPostProcessor类中设置了SpringBeanInfoTest类的属性注入为自动注入(2,默认为0)。我们运行下看看注入情况:

此时发现三种情况都能进行注入

spring bean的自动注入及循环依赖问题怎么解决

此时我们修改注入模型为默认的手动注入。

@Componentpublic class UpdateBeanInfoBeanFactoryPostProcessor implements BeanFactoryPostProcessor{@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {AbstractBeanDefinition a = (AbstractBeanDefinition) beanFactory.getBeanDefinition("a");//a.setAutowireMode(2);//a.getPropertyValues().add("beanDefinitionPropertyValuesBeanTest",new BeanDefinitionPropertyValuesBeanTest());}}

结果打印

spring bean的自动注入及循环依赖问题怎么解决

此时发现第三种方式无法注入了。

那么此时我们再来测试下第四种方式(通过BeanDefinition方式)

我们知道java内省机制最后都是讲解析出来的属性等转换为一个BeanInfo对象,然后所有属性等信息存在一个PropertyDescriptor数组中,而spring中在BeanDefinition中定义了一个MutablePropertyValues对象(propertyValues)中的一个List用来定义描述这个类的属性等,那么我们要往SpringBeanInfoTest中注入一个属性,此时就可以往这个List中存进我们要注入的对象即可。

(其实四种方式都是往propertyValues的List中添加属性内容,最后会对这个list进行统一的处理。只是前三种通过不同方式获取到属性内容,然后放进list,而第四种则是直接add进行)

我们先编写一个测试类(这里不用@Component):

public class BeanDefinitionPropertyValuesBeanTest {}

此时在UpdateBeanInfoBeanFactoryPostProcessor 类中进行BeanDefinition方式的注入:

@Componentpublic class UpdateBeanInfoBeanFactoryPostProcessor implements BeanFactoryPostProcessor{@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {AbstractBeanDefinition a = (AbstractBeanDefinition) beanFactory.getBeanDefinition("a");a.getPropertyValues().add("beanDefinitionPropertyValuesBeanTest",new BeanDefinitionPropertyValuesBeanTest());}}

这里由于是手动的修改BeanDefinition对象,所以其注入模型并不会影响到这个是否生效。

然后在SpringBeanInfoTest中添加注入方法:

@Component("a")public class SpringBeanInfoTest { //@Autowired作用在属性上进行注入@AutowiredAnnotationAutowiredFiledBeanTest autowiredFiledBeanTest; //@Autowired作用在方法上进行注入@Autowiredpublic void setAnnotationAutowiredMethodBeanTest(AnnotationAutowiredMethodBeanTest annotationAutowiredMethodBeanTest){System.out.println("AnnotationAutowiredMethodBeanTest=[{}]"+annotationAutowiredMethodBeanTest);} //使用自动注入(使用byType的模式)public void setAutowiredInjectByTypeMethodBeanTest(AutowiredInjectByTypeMethodBeanTest autowiredInjectByTypeMethodBeanTest){System.out.println("AutowiredInjectByTypeMethodBeanTest=[{}]"+autowiredInjectByTypeMethodBeanTest);} //添加使用BeanDefinition方式进行属性注入public void setBeanDefinitionPropertyValuesBeanTest(BeanDefinitionPropertyValuesBeanTest beanDefinitionPropertyValuesBeanTest){System.out.println("BeanDefinitionPropertyValuesBeanTest=[{}]"+beanDefinitionPropertyValuesBeanTest);} //用来打印@Autowired作用在属性上进行注入是否成功public void printf(){System.out.println("autowiredFiledBeanTest=[{}]"+autowiredFiledBeanTest);} }

我们可以来看看是否生效:

spring bean的自动注入及循环依赖问题怎么解决

可以看是可以进行注入的。

下面我们可以先简单的对这四种情况做个总结,后续再进行源码分析验证猜想:

1)、在一个属性上面加一个@Autowired注解

使用反射机制进行注入,可以看@Autowired源码,伪代码大概如下:

Class clazz = null;Field autowiredFiledBeanTest = clazz.getDeclaredField("autowiredFiledBeanTest");autowiredFiledBeanTest.setAccessible(true);autowiredFiledBeanTest.set(this,getBean(AnnotationAutowiredFiledBeanTest.class));

2)、在一个方法上面加一个@Autowired注解

 2.1如果注入模型是1、2 (自动注入),那么spring底层采用的是java的自省机制发现setter方法然后调用执行
* 也就是说方法上面的@Autowierd注解无用,直接走内省机制进行注入而不是通过解析@Autowierd进行注入

 2.2如果注入模型为0(默认值,手动注入) 那么则是和在属性上面加注解差不多,底层查找所有加了@Autowired注解的方法,然后反射调用method.invoke()
3)、提供一个setter方法,继而把该bean的注入模型改成1、2 自动注入

* 3.1  注入模型是自动注入 则是java的内省机制
伪代码如下:

BeanInfo beanInfo = Introspector.getBeanInfo(SpringBeanInfoTest.class);PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {Method writeMethod = propertyDescriptor.getWriteMethod();writeMethod.invoke(this,getBean(parma))}

4)、使用BeanDefinition方式进行注入

不和注入模型有相关联,即所有情况都能生效

------------------------------------------源码验证

入口:refresh---》

finishBeanFactoryInitialization----》beanFactory.preInstantiateSingletons();---》
getBean---》doGetBean---》createBean-----》doCreateBean----》populateBean
我们进入populateBean方法看看:

//先从容器中获取bean,有则直接返回进行注入//无则调用createBean创建需要进行注入的bean,放进单例池,最后再进行注入protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {if (bw == null) {if (mbd.hasPropertyValues()) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");}else {// Skip property population phase for null instance.return;}} // Give any InstantiationAwareBeanPostProcessors the opportUnity to modify the// state of the bean before properties are set. This can be used, for example,// to support styles of field injection.if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {return;}}}} //1、获取到MutablePropertyValues对象,里面的List<PropertyValue> propertyValueList封装着一些属性的定义//这里现在只能获取到手动使用BeanDefinition动态添加的属性PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null); //获取注入模型int resolvedAutowireMode = mbd.getResolvedAutowireMode();//2、注入模型为1或者2(自动注入),通过内省机制获取所有符合的属性(包括获取到使用了@Autowired注解的set),并getbean放进propertyValueList中if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {MutablePropertyValues newPvs = new MutablePropertyValues(pvs);// Add property values based on autowire by name if applicable.//获取到符合规则的属性(setter)//然后获取到该属性的bean,并加入到MutablePropertyValues中的List中if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {autowireByName(beanName, mbd, bw, newPvs);}// Add property values based on autowire by type if applicable.//获取到符合规则的属性(setter)// 然后获取到该属性的bean,并加入到MutablePropertyValues中的List中if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {autowireByType(beanName, mbd, bw, newPvs);}//所有符合上面的属性都会加到这里pvs = newPvs;} boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE); //3、如果注入模型为0,手动注入,此时这里的propertyValueList只会存在我们手动使用BeanDefinition add进去的。//那么到这里为止所有set方法都没被识别到(既不会在applyPropertyValues中执行了)//下面的循环则是去解析@Autowired作用的属性、方法(反射机制)//注意:如果该属性已经存在propertyValueList,这里则不会对其进行解析(即自动注入模型下@Autowired作用在方法的被忽略执行)PropertyDescriptor[] filteredPds = null;if (hasInstAwareBpps) {if (pvs == null) {pvs = mbd.getPropertyValues();} //获取到所有BeanPostProcessor//如果是InstantiationAwareBeanPostProcessor,即处理@Autowired注解、@Resouce注解、@PostConstruct注解的BeanPostProcessor类型,则完成注入等操作for (BeanPostProcessor bp : getBeanPostProcessors()) {//完成@Autowired作用在属性、方法上面的处理(使用反射)if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;//完成@Autowired作用在属性、方法上面的处理PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {if (filteredPds == null) {filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {return;}}pvs = pvsToUse;}}}if (needsDepCheck) {if (filteredPds == null) {filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}checkDependencies(beanName, mbd, filteredPds, pvs);} //4、处理propertyValueList中的所有还未执行的属性//遍历属性名、对象,内省机制调用invoke方法执行set方法等if (pvs != null) {applyPropertyValues(beanName, mbd, bw, pvs);}}

关于“spring bean的自动注入及循环依赖问题怎么解决”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“spring bean的自动注入及循环依赖问题怎么解决”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注编程网精选频道。

--结束END--

本文标题: spring bean的自动注入及循环依赖问题怎么解决

本文链接: https://lsjlt.com/news/352927.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • spring bean的自动注入及循环依赖问题怎么解决
    这篇文章主要介绍了spring bean的自动注入及循环依赖问题怎么解决的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇spring bean的自动注入及循环依赖问题怎么解决文章都会有所收获,下面我们一起来看看吧...
    99+
    2023-07-05
  • Bean的自动注入及循环依赖问题
    目录一、spring中的各种注入方式一、spring中的各种注入方式 对于是spring的注入前置知识、@Autowired、@Resource等的知识可以看其他文章,这里就不多说了...
    99+
    2023-03-23
    springbean的自动注入方式 循环依赖问题的解决
  • 怎么解决Spring循环依赖问题
    本篇内容介绍了“怎么解决Spring循环依赖问题”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!前言循环依赖...
    99+
    2024-04-02
  • Spring循环依赖问题怎么解决
    在Spring中,循环依赖问题是指两个或多个bean之间出现相互依赖的情况。由于Spring容器默认使用单例模式管理bean,因此循...
    99+
    2023-08-31
    Spring
  • Spring源码是怎么解决Bean的循环依赖
    这篇文章给大家分享的是有关Spring源码是怎么解决Bean的循环依赖的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。首先需要明白一点,只有scop为(singleton)单例类型的Bean,spring才支持循环...
    99+
    2023-06-22
  • 怎么在spring中解决循环依赖问题
    怎么在spring中解决循环依赖问题?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。setter singleton循环依赖使用SingleSetterBeanA依赖Sing...
    99+
    2023-06-08
  • spring循环依赖问题如何解决
    本篇内容介绍了“spring循环依赖问题如何解决”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、三种循环依赖的情况①构造器的循环依赖:这种...
    99+
    2023-07-02
  • 如何解决Spring循环依赖问题
    本文小编为大家详细介绍“如何解决Spring循环依赖问题”,内容详细,步骤清晰,细节处理妥当,希望这篇“如何解决Spring循环依赖问题”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。公共代码package&nbs...
    99+
    2023-07-02
  • 关于spring循环依赖问题及解决方案
    目录一、三种循环依赖的情况比如几个Bean之间的互相引用 甚至自己“循环”依赖自己二、解决方案如何获取依赖三、解决循环依赖必须要三级缓存吗结论四、无...
    99+
    2024-04-02
  • Spring怎么解决循环依赖
    本篇内容介绍了“Spring怎么解决循环依赖”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!写在前面最近,在...
    99+
    2024-04-02
  • springboot怎么解决循环依赖问题
    在Spring Boot中解决循环依赖问题,可以尝试以下几种方法:1. 使用构造器注入:将循环依赖的对象注入到构造器中,并且使用`@...
    99+
    2023-09-27
    springboot
  • 浅入浅出的讲解Spring循环依赖问题
    目录前言概念什么是循环依赖?报错信息通俗版理解两人对峙必须有一人妥协Spring版理解实例化和初始化什么区别?三级缓存创建过程(简易版)创建过程(源码版)最后前言 最近有粉丝...
    99+
    2024-04-02
  • Spring解决循环依赖问题及三级缓存的作用
    目录前言1什么是循环依赖2 如何解决循环依赖3无法解决的循环依赖前言 所谓的三级缓存只是三个可以当作是全局变量的Map,Spring的源码中大量使用了这种先将数据放入容器中等使用结束...
    99+
    2024-04-02
  • Spring Boot循环依赖怎么解决
    本文小编为大家详细介绍“Spring Boot循环依赖怎么解决”,内容详细,步骤清晰,细节处理妥当,希望这篇“Spring Boot循环依赖怎么解决”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧...
    99+
    2023-07-05
  • Spring中怎么处理循环依赖问题
    Spring中怎么处理循环依赖问题,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。什么是循环依赖依赖指的是Bean与Bean之间的依赖关系,循环依赖指的是两个或者...
    99+
    2023-06-20
  • 怎么使用Spring三级缓存解决循环依赖问题
    这篇文章主要介绍了怎么使用Spring三级缓存解决循环依赖问题的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇怎么使用Spring三级缓存解决循环依赖问题文章都会有所收获,下面我们一起来看看吧。循环依赖什么是循环...
    99+
    2023-07-05
  • 关于Spring源码是如何解决Bean的循环依赖
    目录两个单例testA testB 互相依赖的实例化过程Spring容器创建单例“testA”beanSpring容器创建单例“testB”bean源码中的实现方式首先了解一下创建B...
    99+
    2024-04-02
  • Spring解决循环依赖问题及三级缓存的作用是什么
    本文小编为大家详细介绍“Spring解决循环依赖问题及三级缓存的作用是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“Spring解决循环依赖问题及三级缓存的作用是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知...
    99+
    2023-07-02
  • Spring使用三级缓存解决循环依赖的问题
    Spring如何使用三级缓存解决循环依赖在没开始文章之前首先来了解一下什么是循环依赖 @Component public class A { @Autowired ...
    99+
    2024-04-02
  • 如何解决Java循环依赖的问题
    今天就跟大家聊聊有关如何解决Java循环依赖的问题,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。最近看到一个问题:如果有两个类A和B,A类中有一个B的对象b,B类中有一个A的对象a,...
    99+
    2023-06-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作