No bean named 'delegatingFilterProxy' available

这两天在跑一个spring mvc + spring session项目时发现应用启动时报了上面的那个错误,当然,我认为这个错误在spring security中应该也很常见,一般报错:"No bean named 'springSecurityFilterChains' available"

其实上面的错误都是由于DelegatingFilterProxy这个Filter引起的。下面我会简单介绍一下这个错误因为什么引起的,同时给出解决方案。

spring session出错原因:

我相信很多人的web.xml配置应该是这样的:

<filter>
        <filter-name>delegatingFilterProxy</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>delegatingFilterProxy</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

上面的配置是错误的,tomcat启动时首先加载配置文件中Filter,看到我们注册了DelegatingFilterProxy(Filter实现类),调用了如下两个核心方法:

@Override
	protected void initFilterBean() throws ServletException {
		synchronized (this.delegateMonitor) {
			if (this.delegate == null) {
				// 如果没有在web.xml中配置<init-param> targetBeanName,这里该属性默认为filter名字,我们前面配置的delegatingFilterProxy
				if (this.targetBeanName == null) {
					this.targetBeanName = getFilterName();
				}
				
				// 这里开始初始化spring容器
				WebApplicationContext wac = findWebApplicationContext();
				if (wac != null) {
                    // 初始化DelegatingFilterProxy实际代理的Filter
					this.delegate = initDelegate(wac);
				}
			}
		}
	}

protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
        // 这里根据我们定义的filterName从spring容器中找bean,也就是找delegatingFilterProxy,但是我们没定义,所以会报bean异常
		Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);
		if (isTargetFilterLifecycle()) {
			delegate.init(getFilterConfig());
		}
		return delegate;
	}

出错的原因在上面注释中阐述的很明白了,下面说解决办法。

spring session出错解决办法:

将上面web.xml中配置改为如下:

<filter>
        <filter-name>delegatingFilterProxy</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <param-name>targetBeanName</param-name>
            <param-value>springSessionRepositoryFilter</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>delegatingFilterProxy</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

spring文档中解释的很清楚,DelegatingFilterProxy就是一个过滤器代理,因为spring容器没有办法管理java ee容器中的实例,所以它通过将代理Filter定义在Java EE容器中,然后将通过该代理Filter的所有请求委托给spring容器中Filter,这就是DelegatingFilterProxy的本质作用。前面由于我们没有定义targetBean,spring默认取当前filter-name作为委托Filter,但是由于spring容器中并未定义DelegatingFilterProxy这个bean,所以报bean创建异常。因为spring session说白了就是做session共享,核心Filter为SpringSessionRepositoryFilter,这个类spring session已经默认配置在了SpringHttpSessionConfiguration中了,spring容器启动时就注册进了,所以调用getBean当然没问题,它也就是我们DelegatingFilterProxy最终要委托的对象。

 

spring security中出错原因:

有同学用过spring security可能会想到,在spring security中并没有像上面那样定义呀!spring security定义如下:

<filter>
            <filter-name>springSecurityFilterChain</filter-name>
            <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>springSecurityFilterChain</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>

首先说明一下,上面配置是正确的,回到上面问题,这里DelegationFilterProxy并没有定义targetBean初始化阐述啊,为什么又可以呢?因为前面有一段代码是这样:

// 这里根据我们定义的filterName从spring容器中找bean,也就是找springSecurityFilterChain,但是我们没定义,spring security仍不会报错
		Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);

因为在webApplicationContext调用getBean过程中,会对beanName进行显式转换,AbstractBeanFactory中调用代码片段如下:

protected <T> T doGetBean(
			final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
			throws BeansException {
        // 显式转换beanName
		final String beanName = transformedBeanName(name);
        
        ...
}

因为有些bean可能定义了一些别名,spring也会根据别名找到正确的bean。答案也就在这里,spring security确实给DelegatingFilterProxy设置了别名,还是在xml文件解析过程中做的。代码段见下:HttpSecurityBeanDefinitionParser#registerFilterChainProxyIfNecessary

static void registerFilterChainProxyIfNecessary(ParserContext pc, Object source) {
		// ...省略前面代码

		pc.registerBeanComponent(new BeanComponentDefinition(fcpBean,
				BeanIds.FILTER_CHAIN_PROXY));
        // spring将springSecurityFilterChain注册别名org.springframework.security.filterChainProxy
		pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY,
				BeanIds.SPRING_SECURITY_FILTER_CHAIN);
	}

又由于spring容器初始化时已经进行了org.springframework.security.filterChainProxy这个bean的初始化,初始化的实例就是FilterChainProxy实例,它也是spring security核心过滤器链。所以在DelegatingFilterProxy中调用getBean("springSecurityFilterChain", Filter.class)能正常返回而不会报bean创建异常。

模拟spring security `No bean named 'springSecurityFilterChains' available`错误:

看过前面解释的同学应该已经知道如何模拟出现该错误了吧,因为spring注册别名时已经将filterName -> beanName定义死了,也就是我只认识springSecurityFilterChain这个<filter-name>,如果我把<filter-name>随便改一下,spring均会报找到不bean异常。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值