shiro web应用入口之EnvironmentLoaderListener类

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u014316026/article/details/82564385

EnvironmentLoaderListener 是shiro web应用的入口, 它是一个 ServletContext 的监听器, 用于监听容器的启动和关闭事件, 分别对应它的两个方法, contextInitialized(ServletContextEvent sce) 和contextDestroyed(ServletContextEvent sce), 可以从 ServletContextEvent 中直接获取 ServletContext.
请参考: http://shiro.apache.org/static/1.4.0/apidocs/org/apache/shiro/web/env/EnvironmentLoaderListener.html

我们通过在 web.xml 中定义下列代码来设置shiro web应用的入口

<listener>
     <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>

查看 EnvironmentLoaderListener 的源码我们可以发现, 真正用来处理逻辑的是它的父类 EnvironmentLoader, EnvironmentLoader 通过 initEnvironment
(ServletContext servletContext) 方法来初始化Shiro运行所需要的环境.

接下来我们就来看下 EnvironmentLoader 这个类. 我们先来看看这个类之中两个关键的变量

public static final String ENVIRONMENT_CLASS_PARAM = "shiroEnvironmentClass";

public static final String CONFIG_LOCATIONS_PARAM = "shiroConfigLocations";

shiroEnvironmentClass : 用来在 web.xml 中设置自定义的 WebEnvironment 具体实现类. 默认实现类是 IniWebEnvironment.
shiroConfigLocations : 用来在 web.xml 中指定 WebEnvironment 的配置文件. 默认路径是
1. /WEB-INF/shiro.ini
2. classpath:shiro.ini
我们来举个列子:

<context-param>
     <param-name>shiroEnvironmentClass</param-name>
     <param-value>com.foo.bar.shiro.MyWebEnvironment</param-value>
</context-param>
<context-param>
     <param-name>shiroConfigLocations</param-name>
     <param-value>/WEB-INF/someLocation/shiro.ini</param-value>
</context-param>

我们看下这个类的入口方法initEnvironment(ServletContext servletContext)方法(去掉了日志输出等代码)

public WebEnvironment initEnvironment(ServletContext servletContext) throws IllegalStateException {

    // 确保 WebEnvironment 在 ServletContext 中只能创建一次
    if (servletContext.getAttribute(ENVIRONMENT_ATTRIBUTE_KEY) != null) {
        String msg = "There is already a Shiro environment associated with the current ServletContext.  " +
                "Check if you have multiple EnvironmentLoader* definitions in your web.xml!";
        throw new IllegalStateException(msg);
    }
    try {
        // 创建 WebEnvironment
        WebEnvironment environment = createEnvironment(servletContext);
        // 将 WebEnvironment 放入 ServletContext 中
        servletContext.setAttribute(ENVIRONMENT_ATTRIBUTE_KEY,environment);
        return environment;
    } catch (RuntimeException ex) {
        log.error("Shiro environment initialization failed", ex);
        servletContext.setAttribute(ENVIRONMENT_ATTRIBUTE_KEY, ex);
        throw ex;
    } catch (Error err) {
        log.error("Shiro environment initialization failed", err);
        servletContext.setAttribute(ENVIRONMENT_ATTRIBUTE_KEY, err);
        throw err;
    }
}

我们可以发现逻辑处理的主要实现实际上在createEnvironment(ServletContext sc)方法中, 那么我们再来看下createEnvironment(ServletContext sc)方法.

protected WebEnvironment createEnvironment(ServletContext sc) {

    // 确定用来创建 WebEnvironment 的具体实现类, 默认实现类是 IniWebEnvironment
    WebEnvironment webEnvironment = determineWebEnvironment(sc);
    // 确保 webEnvironment 实现了 MutableWebEnvironment 接口
    if (!MutableWebEnvironment.class.isInstance(webEnvironment)) {
        throw new ConfigurationException("Custom WebEnvironment class [" + webEnvironment.getClass().getName() +
                "] is not of required type [" + MutableWebEnvironment.class.getName() + "]");
    }

    // 获取 web.xml 中的 shiroConfigLocations 配置
    String configLocations = sc.getInitParameter(CONFIG_LOCATIONS_PARAM);
    boolean configSpecified = StringUtils.hasText(configLocations);

    // 判断 web.xml 中是否有配置 shiroConfigLocations, 并确保 WebEnvironment 的实现类实现了 ResourceConfigurable 接口
    if (configSpecified && !(ResourceConfigurable.class.isInstance(webEnvironment))) {
        String msg = "WebEnvironment class [" + webEnvironment.getClass().getName() + "] does not implement the " +
                ResourceConfigurable.class.getName() + "interface.  This is required to accept any " +
                "configured " + CONFIG_LOCATIONS_PARAM + "value(s).";
        throw new ConfigurationException(msg);
    }

    MutableWebEnvironment environment = (MutableWebEnvironment) webEnvironment;

    // 将 ServletContext 放入该 WebEnvironment 实例中
    environment.setServletContext(sc);

    if (configSpecified && (environment instanceof ResourceConfigurable)) {
        ((ResourceConfigurable) environment).setConfigLocations(configLocations);
    }

    // 空方法 忽略
    customizeEnvironment(environment);

    // WebEnvironment 初始化
    LifecycleUtils.init(environment);

    return environment;
}

总结:
1. 通过在 web.xml 中配置licenser, 可以使容器在启动时, 通过 EnvironmentLoaderListener 类拿到 ServletContext, 然后通过其父类 EnvironmentLoader 去创建 WebEnvironment
2. EnvironmentLoader 会根据 web.xml 中配置的 shiroEnvironmentClass 去找到对应的 WebEnvironment 实现类, 如果没有配置, 默认使用 IniWebEnvironment 类, 要求自定义的 WebEnvironment 实现类必须实现MutableWebEnvironment 接口.
3. EnvironmentLoader 会根据 web.xml 中配置的 shiroConfigLocations 去找到对应的shiro配置文件, 如果没有配置, 默认先去找 /WEB-INF/shiro.ini, 如果还没有, 再去找 classpath:shiro.ini
4. 最后执行 WebEnvironment 实现类的初始化操作

展开阅读全文

没有更多推荐了,返回首页