Spring框架使用ByName自动注入同名问题剖析
问题描述
我们在使用spring框架进行项目开发的时候,为了配置Bean的方便经常会使用到Spring当中的Autosire机制,Autowire根据注入规则的不同又可以分为==ByName==和==ByType==这两种机制(两者的用法和区别可以参考Spring@Autowire官方文档)。但大家在使用Autowire当中==ByName==机制的时候有没有思考过这样一个问题,当我们配置了两个name属性相同的Bean,Spring在自动注入的时候会采取怎样处理方式?会覆盖?还是抛出异常?还是其他的方式?
实例验证
要得到上面的问题的答案,最简答的方案就是写实列进行验证咯~我们先在Spring中配置两个同名的Bean,配置信息如下:
<bean name="test1" class="com.yanxiao.Test1">
<property name="age" value="20" />
</bean>
<bean name="test1" class="com.yanxiao.Test1">
<property name="age" value="21" />
</bean>
接下来运行程序加载该配置文件,会发现Spring可以正常启动,于是乎我们之前关于抛出异常的假设是错误的。在程序当中获得获得自动注入的名称为test1的Bean对象打印其age属性,发现输出的结果是21,说明==对于同名的BeanSpring会采取覆盖的策略,后面配置的Bean会覆盖掉前面配置的Bean对象。==
看到这里我们最初的问题已经得到了解答,但这个问题难到不值得我们继续思考下去吗?Spring这种强制的覆盖措施真的合理吗,有些情况下由于开发人员的疏忽在没有意识的情况下导致了同名现象的产生,直接覆盖所导致的一些错误会为开发人员的排查错误带来很大的难度?
那么如何解决这个问题呢?靠开发人员的自律?不定义重复名称的bean?我觉得这个是非常不靠谱的,因为项目依赖可能比较复杂,开发人员不尽相同.所以我认为只有通过在程序中引入一种报错机制才能解决这个问题。
Spring既然作为一款优秀的开源框架,其内部除了覆盖之外有没有提供其他的如报错机制等方案供我们选择呢?
源码剖析
带着上面的问题,我们对验证程序进行单步跟踪,从源码的角度了解Spring内部的处理机制是怎样的。
当我们跟踪当Bean注册阶段,执行DefaultListableBeanFactory类的registerBeanDefinition(String beanName, BeanDefinition beanDefinition)方法时,发现有一个==allowBeanDefinitionOverriding==属性。
synchronized (this.beanDefinitionMap) {
Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
if (!this.allowBeanDefinitionOverriding) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
else {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
}
else {
this.beanDefinitionNames.add(beanName);
this.frozenBeanDefinitionNames = null;
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
观察这段代码的逻辑我们可以发现,Spring框架中自动注入遇到同名Bean时其实提供了不同的方案供我们选择,一种是我们之前已经验证过的覆盖措施,通过观看源码我们发现:其实==采用覆盖方案的话如果我们的项目中有日志打印支持的话,Spring也会提供info级别的日志信息。==另一种便是抛出异常的方式。
项目实践
通过上面的源码,我们知道了Spring框架提供了一种开发人员必须解决id或者name重复的问题后才能成功启动容器的自动注入处理方法,这个方案在有些保证项目高可靠的情况下还是十分有用的,那么该怎样选取这种同名抛异常的处理机制呢?
问题的关键就在于我们应该如何改变allowBeanDefinitionOverriding属性的值,通过查阅文档了解到两种方案供大家参考:
方案一
1、自己写一个继承ContextLoaderListener的listener,比如SpringContextLoaderListener,然后重写方法customizeContext,如
public class SpringContextLoaderListener extends ContextLoaderListener {
@Override
protected void customizeContext(ServletContext servletContext, ConfigurableWebApplicationContext applicationContext) {
super.customizeContext(servletContext, applicationContext);
XmlWebApplicationContext context = (XmlWebApplicationContext) applicationContext;
context.setAllowBeanDefinitionOverriding(false); //在这里将XmlWebApplicationContext属性allowBeanDefinitionOverriding设置为false,这个属性的值最终
//会传递给DefaultListableBeanFactory类的allowBeanDefinitionOverriding属性
}
}
2、在web.xml使用自定义的listener,配置如下:
<listener>
<listener-class>com.zyr.web.spring.SpringContextLoaderListener</listener-class>
</listener>
这样,在项目启动时,不同配置文件中如果有同名id或者name的bean,直接抛异常,容器停止启动,到达我们的预期效果。
其实我们的目的仅仅是更改一个属性值,方案一这种自己写一个listener的方法还是有点麻烦。下面还有一种相较更为简便的方案
方案二
1、创建一个实现接口ApplicationContextInitializer的类,如SpringApplicationContextInitializer,代码如下:
public class SpringApplicationContextInitializer implements ApplicationContextInitializer<XmlWebApplicationContext> {
public void initialize(XmlWebApplicationContext applicationContext) {
applicationContext.setAllowBeanDefinitionOverriding(false);//在这里将XmlWebApplicationContext属性allowBeanDefinitionOverriding设置为false,这个属
//性的值最终会传递给DefaultListableBeanFactory类的allowBeanDefinitionOverriding属性
}
}
2、在web.xml文件中添加配置
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>com.zyr.web.spring.SpringApplicationContextInitializer</param-value>
</context-param>
- 顶
- 0
- 踩
- 0
Spring框架使用ByName自动注入同名问题剖析的更多相关文章
- Quartz与Spring集成 Job如何自动注入Spring容器托管的对象
在Spring中使用Quartz有两种方式实现:第一种是任务类继承QuartzJobBean,第二种则是在配置文件里定义任务类和要执行的方法,类和方法可以是普通类.很显然,第二种方式远比第一种方式来的 ...
- Spring框架学习之依赖注入
Spring框架从2004年发布的第一个版本以来,如今已经迭代到5.x,逐渐成为JavaEE开发中必不可少的框架之一,也有人称它为Java下的第一开源平台.单从Spring的本身来说,它贯穿着整个表现 ...
- Spring框架使用@Autowired自动装配引发的讨论
问题描述 有同事在开发新功能测试时,报了个错,大致就是,在使用 @Autowired 注入时,某个类有两个bean,一个叫a,一个叫b. 一般这种情况应该声明注入哪个bean,他没有声明,他不知道这个 ...
- spring mvc:属性无法自动注入
在使用spring mvc 3开发一个项目模块时,遇到这样一个奇怪的问题: 前端页面发送的请求中,所有参数都无法自动注入到指定的@ModelAttribute对象中,经过检查,参数名称与接受对象的属性 ...
- spring boot测试类自动注入service或dao
使用Spring Boot进行单元测试时,发现使用@Autowired注解的类无法自动注入,当使用这个类的实例的时候,报出NullPointerException,即空指针异常. Spring Boo ...
- Spring Boot @Autowired 没法自动注入的问题
Application 启动类: @SpringBootApplication @EnableConfigurationProperties @ComponentScan(basePackages = ...
- web 工程中利用Spring的 ApplicationContextAware接口自动注入bean
最常用的办法就是用 ClassPathXmlApplicationContext, FileSystemClassPathXmlApplicationContext, FileSystemXmlApp ...
- quartz整合spring框架service层对象注入为null解决方案
Job实现类代码 package cn.itcast.quartz; import org.quartz.Job; import org.quartz.JobExecutionContext; imp ...
- Spring框架学习08——自动代理方式实现AOP
在传统的基于代理类的AOP实现中,每个代理都是通过ProxyFactoryBean织入切面代理,在实际开发中,非常多的Bean每个都配置ProxyFactoryBean开发维护量巨大.解决方案:自动创 ...
随机推荐
- 007-Java可变个数形参重载【数组和...】
重载方法时,可变个数形参的方法有两种方式 数组重载 ...重载 对两种方法,其实是一致的,示例如下: public class MethodArgsTest { //可变个数形参的格式:数据类型... ...
- JAVA API about HTTP 2
import java.io.IOException; import java.nio.charset.Charset; import java.security.KeyManagementExcep ...
- 网络请求NSLog结果不全
碰到了两次 NSLog请求结果只有一部分 如果NSLog语句中没有汉语就可以全部输出了,不清楚原因. NSLog(@"%@",object);//这样结果是全的 NSLog(@&q ...
- nginx代理配置备份
补充: 代理对文件大小的限制, server {client_max_body_size 100M;listen 9096;server_name gate.chaohuoyy.com; locati ...
- dubbo重连机制会不会造成错误
dubbo在调用服务不成功时,默认会重试2次. Dubbo的路由机制,会把超时的请求路由到其他机器上,而不是本机尝试,所以 dubbo的重试机器也能一定程度的保证服务的质量. 但是如果不合理的配置重试 ...
- thinkphp 模板继承
模板继承是一项更加灵活的模板布局方式,模板继承不同于模板布局,甚至来说,应该在模板布局的上层.模板继承其实并不难理解,就好比类的继承一样,模板也可以定义一个基础模板(或者是布局),并且其中定义相关的区 ...
- spring中使用RabbitMQ
常见的消息中间件产品: (1)ActiveMQ ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息总线.ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS P ...
- 小程序修改默认的radio样式
1.wxml: <radio-group class="radio-group" bindchange="radioChange"> <vie ...
- System.Web.HttpContext.cs
ylbtech-System.Web.HttpContext.cs 1.程序集 System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken ...
- iOS开发UIMotionEffect运动视觉效果
1.UIMotionEffect简介 在iOS7.0推出了UIMotionEffect运动视觉效果,就是从屏幕偏移不同角度.看到的效果不同! NS_CLASS_AVAILABLE_IOS(7_0) @ ...