在filter等非spring环境中获取spring bean及org.springframework.beans.factory.NoSuchBeanDefinitionException错误

19 篇文章 0 订阅
15 篇文章 0 订阅

小编也是由于一些功能需求需要在filter中获取spring bean但是遇到了一些问题,在此与大家分享一下

    首先我在我的项目中配置了applicationContext.xml与dispatcher-servlet.xml,applicationContext.xml是针对全局配置,dispatcher-servlet.xml针对spring mvc做配置,但是我只在applicationContext.xml中配置了包的扫描。

<context:component-scan base-package="znck.spring.*"/><!-- 注解支持,添加要扫描的包 -->

要获取spring的bean首先我先说一下spring的BeanFactory,spring中bean是有BeanFactory创建管理的,ApplicationContext则是继承了BeanFactory,使得我们可以通过xml配置的方式来实现bean的管理并且ApplicationContext实现了在spring初始化时实例化的Bean,而BeanFactory则是在第一次访问时实例化Bean。ApplicationContext与BeanFactory均有一个重要的方法getBean()用以获取spring bean。那么我们解决如何获取ApplicationContext就可以解决如何获取spring bean的问题了,为此spring提供了一个机制ApplicationContextAware接口spring bean实现该接口就可以获取到ApplicationContext我实现如下:

package znck.spring.serviceImp.util;

import org.springframework.beans.BeansException;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class SpringContextHolder implements ApplicationContextAware {

	private static ApplicationContext applicationContext;
	
	@Override
	public void setApplicationContext(ApplicationContext arg0) throws BeansException {
		// TODO Auto-generated method stub
		SpringContextHolder.applicationContext = arg0;

	}
	
	 /** 
           * 从静态变量applicationContext中得到Bean, 自动转型为所赋值对象的类型. 
      */
	public static Object getBean(String name) { 
		return getApplicationContext().getBean(name);
		} 
	
	/** 
         * 从静态变量applicationContext中得到Bean, 自动转型为所赋值对象的类型. 
     */ 
     public static <T> T getBean(Class<T> requiredType) {
    	 return getApplicationContext().getBean(requiredType); 
    	 } 
     
     
     public static ApplicationContext getApplicationContext() { 
    	 return applicationContext; 
    	 }

}

另外注意一定要将该实现类注册为spring bean组件在xml配置文件中或者使用@Component注解(注解时一定要扫描该包),当ApplicationContext初始化bean时会自动扫描实现了ApplicationContextAware接口的类,并调用setApplicationContext(ApplicationContext arg0)方法将自己本身传递给该实例(另外重复扫描会导致第二次扫描重新传入新的ApplicationContext,可以使用applicationContext.getId();尝试),并且将ApplicationContext对象存储在static对象中,使得其他对象可以直接访问ApplicationContext以获取spring bean。基本获取spring bean的方式就是如此。

    愚蠢的小编总是遇到各种别的麻烦,我在文章开头说了我项目中配置applicationContext.xml和dispatcher-servlet.xml并且没有在dispatcher-servlet.xml添加注解扫描,其实applicationContext.xml配置的是spring IOC容器,dispatcher-servlet.xml配置的是springmvc IOC容器,springmvc是spring的子容器,spring中子容器可以访问父容器中的bean但是父容器不能访问子容器中的bean,另外SpringAOP代理也会导致获取bean失败,如果你使用getBean(Class<T> class);方法获取容器中的bean的话,比如你给service层添加了@Transactional注解的话,由于@Transactional注解时采用AOP代理,实际上容器中的相应的bean是代理类所生成的实例,所以你通过被代理类的类型来获取bean会失败报org.springframework.beans.factory.NoSuchBeanDefinitionException错误,只能通过getBean(String beanName);方法来获取bean,并且如果是通过接口代理方式的话,那么强制转化时只能转化为对应的接口类型。这是因为无论是原类还是代理类都继承了相应的接口,相关请自行查看JDK动态代理。我总结了一下关于获取bean问题的一些错误如下:

(1)使用了AOP代理,还使用getBean(Class<T> class);方法获取容器中的bean。

UserService userServiceImp = (UserService) SpringContextHolder.getBean("userServiceImp");
		SystemService systemServiceImp = (SystemService) SpringContextHolder.getBean("systemServiceImp");



(2)在applicationContext.xml和dispatcher-servlet.xml中都配置了扫描相同的包
         这种做法会导致SpringMVC配置覆盖spring配置,导致部分功能失效,比如你在spring中配置了事物管理机制,并扫描了相关@Transactional注解的包,又在springmvc中也扫描的相关的包,但是却没有在springmvc中配置事物管理,会导致springmvc在IOC容器中生成相同的bean,即把spring响应的bean覆盖掉了,但是springmvc生成的bean是没有织入事物管理机制的,于是会导致事物管理不可以用,反映报错即为事物无法获得。

    另外除了以上方式还有别的方式可以获取spring bean特别是在web项目中spring提供了WebApplicationContext类,专门用于在web程序中获取spring bean。WebApplicationContext是继承了ApplicationContext类,并且spring初始化时将其作为属性放到了servletContext中,是web程序可以通过servletContext获取到WebApplicationContext进而获取spring bean,属性key为WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,使用方式如下

//两种方式作用一致,此为web方式
		wac = (WebApplicationContext) fConfig.getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
		//wac = WebApplicationContextUtils.getWebApplicationContext(fConfig.getServletContext());

wac.getBean(UserServiceImp.class);

相关链接如下

applicationContext.xml和dispatcher-servlet.xml的区别

ApplicationContextAware接口的作用

Spring重复扫描导致事务失败的解决方案及深入分析

spring注解与springMVC注解扫描的问题

SpringMVC通过ApplicationContext得到动态代理报错问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

楼兰小石头

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值