记住我-数据库版(不重要)⭐⭐⭐出错啦⭐⭐⭐
其实文章:记住我-数据库版(不重要)步骤思路整个流程啥的没问题的!
在这里表扬自己一下代码大体思路很清晰。
慢慢的自己敲代码的时候就出现了各种错误
第一个错误: No bean named 'springSecurityFilterChain' available
这是看服务器日志发现的错误点:
09-Nov-2020 00:49:40.691 严重 [RMI TCP Connection(3)-127.0.0.1] org.apache.catalina.core.StandardContext.filterStart Exception starting filter [springSecurityFilterChain]
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'springSecurityFilterChain' available
我看到的第一眼就知道的是spring的bean没有配好。但是的确不知道问题出在哪儿了!因为springSecurity我用的是基于注解的配置。按理来说这错误bean是被我这个注解配置类给注入进来了呀!一直纠结这个点就让我有了很多想法:
1. 首先我就回去pom.xml中看看包是不是齐全,然后查看了包是不是冲突导致的。
导入的包是多少都会存在冲突,依赖优先级自动会排除冲突。虽然我没有见过真的依赖冲突。。。
2. 然后我就去看我的spring的配置文件是不是写错了
<!--配置数据源:用来连接数据库的-->
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
<property name="username" value="root"></property>
<property name="password" value="root"></property>
<property name="url" value="jdbc:mysql://localhost:3306/springsecurity_demo?useSSL=false"></property>
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
</bean>
<!--jdbcTemplate:用来操作数据库的-->
<bean class="org.springframework.jdbc.core.JdbcTemplate" name="jdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
看完是没有问题的。
3. 又去看web.xml中是否配置了spring上下文监听器监听我这配置文件
<!--全局参数-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--spring上下文对象监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
...
也是没问题!甚至考虑到了是不是配置文件名字的问题(不是名字的问题),之前我的配置文件名:spring.xml。然后又改成了applicationContext.xml的。。。
4. 启动还是报错,问题就是没有加载到我这个applicationContext.xml文件。既然spring-mvc.xml文件都能加载到为啥我这不能!于是我。。。
把我applicationContext.xml文件import到spring-mvc.xml文件中
<!--注解扫描-->
<context:component-scan base-package="com.zhoujinyuan.springsecurity"></context:component-scan>
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--spring mvc注解驱动-->
<mvc:annotation-driven></mvc:annotation-driven>
<mvc:default-servlet-handler/>
<import resource="applicationContext.xml"></import>
启动结果好了。卧槽!然后还是不知道问题在哪儿!!!我就可纳闷~~~~~
5. 不放弃的我,又去搜了<context-param>
和<init-param>
的区别!因为都是指定配置文件位置的标签么~
<context-param>
当服务器启动时,服务器会为每一个WEB应用创建一个唯一的ServletContext对象代表WEB应用。每一个web应用中的servlet共享一个ServletContext,所以Servlet之间就可以通过该对象来实现数据通信。而这个标签就是定义在ServletContext域中的参数值,服务器启动监听会将Spring应用上下文对象存到ServletContext域中,共所有的servlet使用。全局参数!!!
<init-param>
这个却是Servlet范围内的参数,只能在Sercvlet的init()的方法中取得。不是全局的!因为配的是DispatcherServlet!所以在DispatcherServlet的servlet范围使用。
心得
既然都是spring的配置文件,我的理解是都可以写在同一个xml文件下的!只不过全局参数的配置加载时机不一样。早晚的事儿。处于三层架构思想就是各管各的事儿。才有了spring和springmvc配置文件这一说。不过也让我学到了不少内容。还有就是自己不太会总结。嘴笨:意思就是给别人讲不明白~
6. 言归正传,因为我始终坚信一点:我很菜,对于框架和自己写的代码,出了错,我宁可相信框架也不相信自己写的代码。肯定是我自己哪儿没写对!
于是我就参看了文章1和自己仔细理解,慢慢发现原因就是没有给spring配置文件加入包扫描
<!--包扫描-->
<context:component-scan base-package="com.zhoujinyuan.springsecurity"></context:component-scan>
....
我吐了。。。 我发誓:日后只要写SSM不管三七二十一先开启包扫描!
第一个错误我来补充了
问题的根本原因是:DelegatingFilterProxy 初始化时需要到 IOC 容器查找一个 bean, 这个 bean 所在的 IOC 容器要看是谁扫描了 SpringSecurityConfig 。
如果是 Spring 扫描了 WebAppSecurityConfig,那么 Filter 需要的 bean 就在 Spring 的 IOC 容器。如果是 SpringMVC 扫描了 WebAppSecurityConfig,那么 Filter 需要的 bean 就在 SpringMVC 的 IOC 容器。
明确三大组件启动顺序
- 首先:ContextLoaderListener 初始化,创建 Spring 的 IOC 容器
- 其次:DelegatingFilterProxy 初始化,查找 IOC 容器、查找 bean
- 最后:DispatcherServlet 初始化,创建 SpringMVC 的 IOC 容器
烦烦烦
第二个错误:org.apache.catalina.core.StandardContext.listenerStart Error configuring application listener of class [org.springframework.web.context.ContextLoaderListener]
ContextLoaderListener类出错
好说:配置没问题,肯定就是少了导包。
<!--这个类是spring-web包下的!导入即可! -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
知识点:关于注解配置类如何在web.xml配置
参看文章就可
在web.xml
你需要引导上下文AnnotationConfigWebApplicationContext
:
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
org.package.YouConfigurationAnnotatedClass
</param-value>
</init-param>
</servlet>
并且不要忘了使用@EnableWebMvcMVC
注释。
EDIT as a “comments follow up” => to be Turing Complete:
是的,你当然需要听众。尽管以上内容完全回答了“ 如何在Web.xml中注册Spring @Configuration
带注释的类而不是applicationContext.xml文件 ”的问题,但这是Spring官方文档中的一个示例,其布局完整web.xml
:
<web-app>
<!-- Configure ContextLoaderListener to use AnnotationConfigWebApplicationContext
instead of the default XmlWebApplicationContext -->
<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
<!-- Configuration locations must consist of one or more comma- or space-delimited
fully-qualified @Configuration classes. Fully-qualified packages may also be
specified for component-scanning -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.acme.AppConfig</param-value>
</context-param>
<!-- Bootstrap the root application context as usual using ContextLoaderListener -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Declare a Spring MVC DispatcherServlet as usual -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- Configure DispatcherServlet to use AnnotationConfigWebApplicationContext
instead of the default XmlWebApplicationContext -->
<init-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</init-param>
<!-- Again, config locations must consist of one or more comma- or space-delimited
and fully-qualified @Configuration classes -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.acme.web.MvcConfig</param-value>
</init-param>
</servlet>
<!-- map all requests for /app/* to the dispatcher servlet -->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
</web-app>