博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring中修改allowBeanDefinitionOverriding和allowCircularReferences属性的两种方式
阅读量:2490 次
发布时间:2019-05-11

本文共 9249 字,大约阅读时间需要 30 分钟。

allowBeanDefinitionOverriding属性含义

设置是否允许通过注册具有相同名称的不同定义来覆盖bean定义,并自动替换前者。否则,将引发异常。默认值为“true”。

allowCircularReferences属性含义

设置是否允许bean之间的循环引用并自动尝试解析它们。

默认值为“true”。关闭此选项可在遇到循环引用时引发异常,完全不允许循环引用。

循环依赖应该都比较了解,主要看看allowBeanDefinitionOverriding。

public class TestSpring {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean1.xml", "bean2.xml"); User user = (User) applicationContext.getBean("user"); System.out.println("name: " + user.getName()); }}

加载了两个配置文件,并且都配置了id为user的bean对象。

bean1.xml中,name为lisi

bean2.xml中,name为wangwu

根据allowBeanDefinitionOverriding属性的定义,默认值为true,并且相同名称的bean会进行覆盖,所以按照xml文件的加载顺序,bean2会覆盖bean1的配置。

最终输出结果为:name: wangwu

如果交换配置文件的加载顺序

ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean2.xml", "bean.xml");

最终输出结果为:name: lisi

如何修改属性值

方式一:

自定义一个applicationContext,并继承ClassPathXmlApplicationContext,重写customizeBeanFactory方法。

public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {
public MyClassPathXmlApplicationContext(String... configLocations) {
super(configLocations); } @Override protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
super.setAllowBeanDefinitionOverriding(false); super.setAllowCircularReferences(false); super.customizeBeanFactory(beanFactory); }}
public class TestSpring {
public static void main(String[] args) {
MyClassPathXmlApplicationContext applicationContext = new MyClassPathXmlApplicationContext("bean2.xml", "bean1.xml"); User user = (User) applicationContext.getBean("user"); System.out.println("name: " + user.getName()); }}

报错如下,不允许出现定义同名的bean了。

Exception in thread "main" org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to register bean definition with name 'user'Offending resource: class path resource [bean1.xml]; nested exception is org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'user' defined in class path resource [bean1.xml]: Cannot register bean definition [Generic bean: class [com.wyl.learn.User]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [bean1.xml]] for bean 'user': There is already [Generic bean: class [com.wyl.learn.User]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [bean2.xml]] bound.	at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:72)	at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:119)	at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:104)	at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.processBeanDefinition(DefaultBeanDefinitionDocumentReader.java:314)	at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseDefaultElement(DefaultBeanDefinitionDocumentReader.java:197)	at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:176)	at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:149)	at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:96)	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:514)	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:394)	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:337)	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:305)	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:188)	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:224)	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:195)	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:257)	at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:128)	at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:94)	at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:133)	at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:637)	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:522)	at org.springframework.context.support.ClassPathXmlApplicationContext.
(ClassPathXmlApplicationContext.java:144) at org.springframework.context.support.ClassPathXmlApplicationContext.
(ClassPathXmlApplicationContext.java:95) at com.wyl.learn.MyClassPathXmlApplicationContext.
(MyClassPathXmlApplicationContext.java:9) at com.wyl.learn.TestSpring.main(TestSpring.java:5)Caused by: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'user' defined in class path resource [bean1.xml]: Cannot register bean definition [Generic bean: class [com.wyl.learn.User]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [bean1.xml]] for bean 'user': There is already [Generic bean: class [com.wyl.learn.User]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [bean2.xml]] bound. at org.springframework.beans.factory.support.DefaultListableBeanFactory.registerBeanDefinition(DefaultListableBeanFactory.java:927) at org.springframework.beans.factory.support.BeanDefinitionReaderUtils.registerBeanDefinition(BeanDefinitionReaderUtils.java:166) at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.processBeanDefinition(DefaultBeanDefinitionDocumentReader.java:311) ... 21 more

方式二:

直接调用set方法,并重新调用refresh()方法让属性生效,直接会出出现和方式一同样的报错信息。

public class TestSpring {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean2.xml", "bean1.xml"); applicationContext.setAllowBeanDefinitionOverriding(false); applicationContext.setAllowCircularReferences(false); applicationContext.refresh(); User user = (User) applicationContext.getBean("user"); System.out.println("name: " + user.getName()); }}

原理分析

两种方式的关键都在于customizeBeanFactory方法

protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
if (this.allowBeanDefinitionOverriding != null) {
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } if (this.allowCircularReferences != null) {
beanFactory.setAllowCircularReferences(this.allowCircularReferences); } }

spirng在加载过程中,会执行到这段代码,首先判断allowBeanDefinitionOverriding属性是否为null,而这两个属性默认情况下是为null。(包装类型定义的,所以默认为null),所以beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);就不会被执行,

那么在DefaultListableBeanFactory中这两个属性的地方就会取默认值true。(真正使用时是通过DefaultListableBeanFactory类中定义的这个两个属性值获取的)

AbstractRefreshableApplicationContext提供了修改属性的方法,如果重写了方法,那么修改的是DefaultListableBeanFactory中的属性。

在这里插入图片描述

DefaultListableBeanFactory中的属性,默认为true。

在这里插入图片描述

所以第二种方式的原理就是,先通过set方式,让两个属性值不为null,那么就会修改DefaultListableBeanFactory中的属性了。

protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
//不为null,成立,进入if条件修改beanFactory.setAllowBeanDefinitionOverriding(true) if (this.allowBeanDefinitionOverriding != null) {
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } if (this.allowCircularReferences != null) {
beanFactory.setAllowCircularReferences(this.allowCircularReferences); } }

而第一种方式避免了重新调用refresh的过程,是直接在customizeBeanFactory中进行属性赋值,赋值完成后再调用父类的customizeBeanFactory方法继续完成之后的工作,有点类似静态代理模式的运用,重写父类方法,完成自己的业务逻辑之后再调用父类原本的方法。

转载地址:http://xolrb.baihongyu.com/

你可能感兴趣的文章
Django 源码阅读:url解析
查看>>
Docker面试题(一)
查看>>
第一轮面试题
查看>>
2020-11-18
查看>>
Docker面试题(二)
查看>>
一、redis面试题及答案
查看>>
消息队列2
查看>>
C++ 线程同步之临界区CRITICAL_SECTION
查看>>
测试—自定义消息处理
查看>>
MFC中关于虚函数的一些问题
查看>>
根据图层名获取图层和图层序号
查看>>
规范性附录 属性值代码
查看>>
提取面狭长角
查看>>
Arcsde表空间自动增长
查看>>
Arcsde报ora-29861: 域索引标记为loading/failed/unusable错误
查看>>
记一次断电恢复ORA-01033错误
查看>>
C#修改JPG图片EXIF信息中的GPS信息
查看>>
从零开始的Docker ELK+Filebeat 6.4.0日志管理
查看>>
How it works(1) winston3源码阅读(A)
查看>>
How it works(2) autocannon源码阅读(A)
查看>>