当项目中存在2个以上IOC容器时,初始化security框架时会抛出异常
spring ioc父容器 扫描service...
springMVC ioc子容器 扫描controller...
这个异常主要在于哪一个ioc来扫描WebAppSecurityConfig类,
分析问题:
如果spring 扫描 :则Filter在spring ioc容器中
如果springMVC扫描:则Filter在springMVC 容器中
通常情况下使用security都是对请求做权限控制,所以不能由spring ioc容器来进行扫描,进而衍生出下面的异常
分析问题所在:
首先明确三组件加载顺序:
首先contextLoaderListener初始化 创建Spring IOC容器
其次DelegatingFilterProxy初始化 查找ioc容器 创建bean
最后DispatcherServlet初始化 创建springMVC IOC容器
通过debug调试可以确定,在DelegatingFilterProxy初始化时,会查找有没有ioc容器,如果有则继续查找有没有bean,没有bean则抛出上面的异常信息
当没有IOC容器时,则会放弃查找,在第一次请求发出时在次查找ioc容器,也就是dispatcherServlet初始化后再次进行查找,如果找不到ioc容器会抛异常,如果找到会继续查找是否有这个bean
遗憾的是,这次依然找不到,通过Debug调试源码发现,第二次查找时查的依然是spring ioc容器
这个常量表示了永远会找父容器;
两种解决方案
方案一:不使用contextLoaderListener,将两个IOC容器合二为一由DispatcherServlet加载所有spring配置文件
这样会造成DelegatingFilterProxy在初始化时,找不到ioc容器,则放弃,在第一次请求时spring的配置文件全部加载,这是在查找则有了,
问题点:会破坏现有程序结构,原本是 ContextLoaderListener 和 DispatcherServlet两个组件创建两个 IOC 容器,现在改成只有一个。
方案二:修改源码
方法:1.在初始化时直接跳过查找ioc容器的环节
2.第一次请求时直接找springMVC容器
在项目路径下创建同包同类名的DelegatingFilterProxy类
将249行注释掉
WebApplicationContext wac = findWebApplicationContext(); //查找ioc容器
添加自己写的代码
// 获取servletContext对象
ServletContext sc = this.getServletContext();
// 拼接SpringMVC将IOC容器存入servletContext域的时候使用的属性名
String servletName = "dispatcherServlet";
String attrName = FrameworkServlet.SERVLET_CONTEXT_PREFIX+servletName;
WebApplicationContext wac = (WebApplicationContext)sc.getAttribute(attrName);
servletName 具体是什么值参照自己项目中web.xml中配置的dispatcherServlet的servlet-name名;
这时security环境初步搭建完成!