问题原因:

  1. ShiroRelam属于filter即过滤器,它在Spring未完成注入bean之前就已经拦截了,因此无法注入。
  2. 对于SpringBoot,没有将ShiroRealm注入Bean

       分析:spring加载时候,注入的bean 的顺序是 先是Lisener 然后是 Filter 最后是 Servlet

因此如果在过滤器或者监听器里面注入service等会是空,因为在过滤器或者监听器加载的时候

因此为了解决这个问题,现在要进行手动注入

参考链接:1. https://blog.csdn.net/yuanlaijike/article/details/79627836

                  2.https://blog.csdn.net/qiufengzh/article/details/80688790

                  3.https://blog.csdn.net/u010520146/article/details/74025411(推荐)

                  4.https://blog.csdn.net/fightingboyws/article/details/79158630(shiro实现权限管理时遇到的坑)

思路一:

下面代码是工具类,手动注入service,到此问题解决

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

/**
 * spring加载时候,注入的bean 的顺序是 先是Lisener 然后是 Filter 最后是 Servlet
 * 因此如果在过滤器或者监听器里面注入service等会是空,因为在过滤器或者监听器加载的时候
 * Servlet,service等还没有加载,因此是空的,所以就手动注入
 *
 * Created by zhong.h on 2018/6/13/013.
 */
@Component
public class SpringBeanFactoryUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        if (SpringBeanFactoryUtils.applicationContext == null) {
            SpringBeanFactoryUtils.applicationContext = applicationContext;
        }

    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    //根据名称(@Resource 注解)
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }

    //根据类型(@Autowired)
    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }

    public static <T> T getBean(String name, Class<T> clazz) {
        return getApplicationContext().getBean(name, clazz);
    }
}

思路二:

碰到此问题,一开始以为是springmvc注入配置问题,但是controller注入又都正常,此时陷入百思不得解。一项项跟踪,发现原来shiro 自定义realm的认证阶段属于filter,当时的spring bean还没有读取进来。
最后通过配置web.xml文件,把spring mvc的xml提高一点优先级,才最终解决了这个问题。下面是web.xml完整配置:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring-mybatis.xml,classpath:dispatcher-servlet.xml,classpath:spring-shiro.xml</param-value>
  </context-param>
  <servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:dispatcher-servlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <!-- 设置拦截 !-->
  <servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
 
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <context-param>
    <param-name>log4jContextName</param-name>
    <param-value>log4jContext</param-value>
  </context-param>
  <!-- 添加shiro的过滤器代理!-->
  <filter>
     <filter-name>shiroFilter</filter-name>
     <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
     <async-supported>true</async-supported>
    <init-param>
      <param-name>targetFilterLifecycle</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>shiroFilter</filter-name> <!-- 此处必需写成"/*",如果只写"/" ,过滤器没有作用-->
    <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>

执行逻辑

     1 、启动一个 WEB 项目的时候, WEB 容器会去读取它的配置文件 web.xml ,读取 <listener> 和 <context-param> 两个结点。

     2 、紧急着,容创建一个 ServletContext ( servlet 上下文),这个 web 项目的所有部分都将共享这个上下文。

     3 、容器将 <context-param> 转换为键值对,并交给 servletContext 。

     4 、容器创建 <listener> 中的类实例,创建监听器。

web.xml 的加载顺序是: context-param -> listener -> filter -> servlet ,而同个类型之间的实际程序调用的时候的顺序是根据对应的 mapping 的顺序进行调用的。
 

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐