我是靠谱客的博主 纯情路灯,最近开发中收集的这篇文章主要介绍报错解决:No-bean-named-springSecurityFilterChain-available问题描述错误分析解决措施方式二:修改源代码,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

问题描述

在项目中加入Spring Security后,运行web项目,报错:

org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'springSecurityFilterChain' available
		at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:816)
		at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1288)
		at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
		at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207)
		at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1115)
		at org.springframework.web.filter.DelegatingFilterProxy.initDelegate(DelegatingFilterProxy.java:338)
		at org.springframework.web.filter.DelegatingFilterProxy.initFilterBean(DelegatingFilterProxy.java:243)
		at org.springframework.web.filter.GenericFilterBean.init(GenericFilterBean.java:239)
		at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:270)
		at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:251)
		at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:102)
		at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4566)
		at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5203)
		at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
		at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:717)
		at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:690)
		at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:706)
		at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1727)
		at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
		at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
		at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
		at java.base/java.lang.reflect.Method.invoke(Method.java:564)
		at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:288)
		at java.management/com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:809)
		at java.management/com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
		at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:459)
		at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:408)
		at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
		at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
		at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
		at java.base/java.lang.reflect.Method.invoke(Method.java:564)
		at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:288)
		at java.management/com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:809)
		at java.management/com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
		at java.management/com.sun.jmx.remote.security.MBeanServerAccessController.invoke(MBeanServerAccessController.java:468)
		at java.management.rmi/javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1466)
		at java.management.rmi/javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1307)
		at java.base/java.security.AccessController.doPrivileged(AccessController.java:691)
		at java.management.rmi/javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1406)
		at java.management.rmi/javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:827)
		at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
		at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
		at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
		at java.base/java.lang.reflect.Method.invoke(Method.java:564)
		at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:359)
		at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200)
		at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197)
		at java.base/java.security.AccessController.doPrivileged(AccessController.java:691)
		at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196)
		at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:587)
		at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:828)
		at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:705)
		at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
		at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:704)
		at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
		at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
		at java.base/java.lang.Thread.run(Thread.java:832)

错误分析

搭建Spring Security时,创建了一个基于注解的自定义配置类WebAppSecurityConfig(该类必须被扫描,否则将不起作用!)。
Alt
但是在原本的项目中,存在两个IOC容器。

ContextLoaderListener负责了Spring IOC容器的初始化,主要扫描的类是XxxxServiceXxxxMapper类等。

DispatcherServlet负责了SpringMVC IOC容器的初始化,主要负责XxxxHandlerview-controller

而在项目中为了让Spring Security可以针对浏览器的请求进行权限控制,所以需要让SpringMVC来扫描WebAppSecurityConfig配置类

但是在项目启动过程中报错未找到bean,和三大组件的启动顺序相关:

  • 首先:ContextLoaderListener初始化,创建Spring的IOC容器
  • 其次:Delegating初始化,查找IOC容器,查找bean
  • 最后:DispatcherServlet初始化,创建SpringMVC的IOC容器

通过debug发现,按照官方源码的顺序,DelegatingFilterProxy类中只能查找到Spring IOC,但是我们的Spring Security只存在于SpringMVC IOC中,所以必然会报错。

首先进入initFilterBean()方法初始化我们设置的bean,通过findWebApplicationContext方法会调用WebApplicationContextUtils工具类获取得到WebApplicationContextSpring的IOC容器,但是第一次查找并没有找到该bean,此时的delegatenull,初始化失败。doFilter()会在第一次请求的时候继续找IOC容器,由于项目并未启动,所以无法执行doFilter(),因此会始终找不到我们需要的bean,整个项目启动以未找到bean的错误告终,报错No bean named 'springSecurityFilterChain' available
Alt

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
    // Lazily initialize the delegate if necessary.
   Filter delegateToUse = this.delegate;
   if (delegateToUse == null) {
      synchronized (this.delegateMonitor) {
         delegateToUse = this.delegate;
         if (delegateToUse == null) {
            WebApplicationContext wac = findWebApplicationContext();
            if (wac == null) {
               throw new IllegalStateException("No WebApplicationContext found: " +
                     "no ContextLoaderListener or DispatcherServlet registered?");
            }
            delegateToUse = initDelegate(wac);
         }
         this.delegate = delegateToUse;
      }
   }

@Nullable
public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
   return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
}

解决措施

方式一:将Spring的IOC容器和SpringMVC的IOC容器合二为一

web.xml文件中做如下修改:
注释ContextLoaderListener的相关设置

<!--  <context-param>-->
<!--    <param-name>contextConfigLocation</param-name>-->
<!--    <param-value>classpath:spring-persist-*.xml</param-value>-->
<!--  </context-param>-->

<!--  <listener>-->
<!--    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>-->
<!--  </listener>-->

DispatcherServlet启动参数中指定所有的Spring配置文件

<servlet>
    <servlet-name>springDispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring-*.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

Alt
通过debug发现,首先进入initFilterBean方法,然后在doFilter方法中初始化我们的filter成功!原因是在同一个IOC容器中可以找到对应delegate。

方式二:修改源代码

首先新建一个与源代码相同的包,并创建一个类名相同的类,做出如下修改:
Alt
initFilterBean

@Override
protected void initFilterBean() throws ServletException {
    synchronized (this.delegateMonitor) {
        if (this.delegate == null) {
            // If no target bean name specified, use filter name.
            if (this.targetBeanName == null) {
                this.targetBeanName = getFilterName();
            }
            // Fetch Spring root application context and initialize the delegate early,
            // if possible. If the root application context will be started after this
            // filter proxy, we'll have to resort to lazy initialization.
            // 注释以下部分
            /*WebApplicationContext wac = findWebApplicationContext();
            if (wac != null) {
                this.delegate = initDelegate(wac);
            }*/
        }
    }
}

doFilter

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {

    // Lazily initialize the delegate if necessary.
    Filter delegateToUse = this.delegate;
    if (delegateToUse == null) {
        synchronized (this.delegateMonitor) {
            delegateToUse = this.delegate;
            if (delegateToUse == null) {
                // 将原来的查找IOC容器的方法注释掉
                // WebApplicationContext wac = findWebApplicationContext();

                // 按照自己的需要重新编写
                // 1. 获取ServletContext对象
                ServletContext sc = this.getServletContext();

                // 2. 拼接SringMVC将IOC容器存到ServletContext域的容器中
                String servletName = "springDispatcherServlet";
                String attrName = FrameworkServlet.SERVLET_CONTEXT_PREFIX + servletName;

                // 3. 根据attrName从ServletContext域中获取IOC容器对象
                WebApplicationContext wac = (WebApplicationContext) sc.getAttribute(attrName);

                if (wac == null) {
                    throw new IllegalStateException("No WebApplicationContext found: " +
                            "no ContextLoaderListener or DispatcherServlet registered?");
                }
                delegateToUse = initDelegate(wac);
            }
            this.delegate = delegateToUse;
        }
    }

最后

以上就是纯情路灯为你收集整理的报错解决:No-bean-named-springSecurityFilterChain-available问题描述错误分析解决措施方式二:修改源代码的全部内容,希望文章能够帮你解决报错解决:No-bean-named-springSecurityFilterChain-available问题描述错误分析解决措施方式二:修改源代码所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(32)

评论列表共有 0 条评论

立即
投稿
返回
顶部