在spring应用中使用shiro框架关于session解析

先看shiro过滤器的UML
在这里插入图片描述

已经有cookie保存sessionId的请求场景:
1.请求第一次通过shiro的过滤器 OncePerRequestFilter 时,会把request,response包装成ShiroHttpServletRequest和ShiroHttpServletResponse,并且在请求中设置一个属性标识,作用就是当这个请求再次经过过滤器 OncePerRequestFilter 时,不会再包装请求和响应了.

2.请求第一次通过 OncePerRequestFilter 时,会把请求分到 AbstractShiroFilter 过滤器中,看上面的UML图,然后在AbstractShiroFilter中,有下面代码:

final ServletRequest request = this.prepareServletRequest(servletRequest, servletResponse, chain);
final ServletResponse response = this.prepareServletResponse(request, servletResponse, chain);
Subject subject = this.createSubject(request, response);
subject.execute(new Callable() {
    public Object call() throws Exception {
        AbstractShiroFilter.this.updateSessionLastAccessTime(request, response);
        AbstractShiroFilter.this.executeChain(request, response, chain);
        return null;
    }
});

上面的代码分析:
第一行是包装servlet规范的request变成ShiroHttpServletRequest
第二行是包装servlet规范的response变成ShiroHttpServletResponse

第三行是创建当前请求的subject(即当前shiro的subject),有sessionId就创建包含sessionId的subject,没有就创建没有包含sessionId的subject
剩下的就是当前的subject执行shiro配置的过滤器链,这些shiro链中的过滤器,都是继承OncePerRequestFilter 的,所以当前的请求会再次通过OncePerRequestFilter ,当这个请求再次通过OncePerRequestFilter 时,已经在请求中设置了一个属性标识,通过判断这个属性标识,不会再次包装请求和响应,即不会再次包装ShiroHttpServletRequest和ShiroHttpServletResponse

3.回归主题,当执行

Subject subject = this.createSubject(request, response);

这句代码跟踪发现,请求会到 DefaultWebSessionManager 类中,就是session的管理器
在这个类中方法

private Serializable getReferencedSessionId(ServletRequest request, ServletResponse response) {
	String id = this.getSessionIdCookieValue(request, response);
	if (id != null) {
	    request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, "cookie");
	}

上面代码就是从请求过来的cookie中获取sessionId
shiro可以配置自己的cookie模版,把这个模版返回给浏览器,然后当请求过来时,根据这cookie模版的名字获取值sessionId
获取sessionId后,就在请求中设置属性,说请求中的sessionId,是从cookie中获取的,不是新创建的
请求再次设置如下两个属性,说是shiro请求的sessionId,和这个sessionId是有效的

if (id != null) {
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
}

4.从cookie中获取了sessionId后,shiro是怎么获取保存的session的
注意:和session相关的操作,要找shiro中session管理器,因为session管理器是管理session创建,获取,删除的,所以一定要有这样的意识
在DefaultWebSessionManager 的父类中extends DefaultSessionManager
发现如下代码

Session s = this.retrieveSessionFromDataSource(sessionId);


protected Session retrieveSessionFromDataSource(Serializable sessionId) throws UnknownSessionException {
	return this.sessionDAO.readSession(sessionId);
}

可知是找sessionDAO,根据sessionId获取session对象的
sessionDAO是session访问对象,将session保存在缓存中,而session所在的缓存可以是redis或其他

5.shiro框架会先使用sessionDAO根据sessionId获取session,后再调用sessionDAO的create(session)方法,再次保存到缓存中,即相当于更新了session的有效期,访问一次就更新一次

public interface SessionDAO {
    Serializable create(Session var1);

    Session readSession(Serializable var1) throws UnknownSessionException;

    void update(Session var1) throws UnknownSessionException;

    void delete(Session var1);

    Collection<Session> getActiveSessions();
}

一开始访问应用,还没有创建session场景
1.一开始访问shiro框架时,没有cookie,没有sessionId
shiro框架也会看有没有cookie,有没有sessionId

注意:补充重要知识
在请求第一次通过 OncePerRequestFilter 时,会把请求分到 AbstractShiroFilter 过滤器中,
进入

final ServletRequest request = this.prepareServletRequest(servletRequest, servletResponse, chain);
final ServletResponse response = this.prepareServletResponse(request, servletResponse, chain);
Subject subject = this.createSubject(request, response);
subject.execute(new Callable() {
    public Object call() throws Exception {
        AbstractShiroFilter.this.updateSessionLastAccessTime(request, response);
        AbstractShiroFilter.this.executeChain(request, response, chain);
        return null;
    }
});

上面代码除包装request,response和创建subject外,还更新session最新访问时间(如果有)
开始执行shiro中的过滤器链

AbstractShiroFilter.this.executeChain(request, response, chain);

上面这句代码是shiro过滤器链执行的开始,具体怎么做看代码

protected void executeChain(ServletRequest request, ServletResponse response, FilterChain origChain) throws IOException, ServletException {
   FilterChain chain = this.getExecutionChain(request, response, origChain);
   chain.doFilter(request, response);
}

看this.getExecutionChain

protected FilterChain getExecutionChain(ServletRequest request, ServletResponse response, FilterChain origChain) {
    FilterChain chain = origChain;
    FilterChainResolver resolver = this.getFilterChainResolver();
    if (resolver == null) {
        log.debug("No FilterChainResolver configured.  Returning original FilterChain.");
        return origChain;
    } else {
        FilterChain resolved = resolver.getChain(request, response, origChain);
        if (resolved != null) {
            log.trace("Resolved a configured FilterChain for the current request.");
            chain = resolved;
        } else {
            log.trace("No FilterChain configured for the current request.  Using the default.");
        }

        return chain;
    }
}

上面代码就是获取FilterChainResolver ,这个类在shiro框架启动时就把shiro配置的所有属于shiro的每个路径对应的过滤器链集中存放起来,再把tomcat的过滤器链保存shiro过滤器链resolved中,等执行完shiro的过滤器链后,再执行tomcat过滤器链

shiro的过滤器链是 ProxiedFilterChain

ProxiedFilterChain implements FilterChain

2.回归正题,当前请求通过当前请求路径对应的shiro过滤器链集中的一个链后
就到了servlet,即springmvc的dispatcherServlet
在接下来执行中
最终是javax.servlet.http.HttpServletRequestWrapper包装类中,调用ShiroHttpServletRequest中的
在通过shiro过滤器时,就包装了request为ShiroHttpServletRequest

public HttpSession getSession() {
        return this.getSession(true);
}
Session shiroSession = this.getSubject().getSession(create);//由shiro的subject创建
this.session = new ShiroHttpSession(shiroSession, this, this.servletContext);

ShiroHttpSession 是继承 servlet规范的 HttpSession 的,这里将shiro的Session包装,
shiro最后调用SessionDAO保存session
这样传到controller层的时候,使用的就是shiro的Session

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
torch.save(model.state_dict(), r'./saved_model/' + str(args.arch) + '_' + str(args.batch_size) + '_' + str(args.dataset) + '_' + str(args.epoch) + '.pth') # 计算GFLOPs flops = 0 for name, module in model.named_modules(): if isinstance(module, torch.nn.Conv2d): flops += module.weight.numel() * 2 * module.in_channels * module.out_channels * module.kernel_size[ 0] * module.kernel_size[1] / module.stride[0] / module.stride[1] elif isinstance(module, torch.nn.Linear): flops += module.weight.numel() * 2 * module.in_features start_event = torch.cuda.Event(enable_timing=True) end_event = torch.cuda.Event(enable_timing=True) start_event.record() with torch.no_grad(): output = UNet(args,3,1).to(device) end_event.record() torch.cuda.synchronize() elapsed_time_ms = start_event.elapsed_time(end_event) gflops = flops / (elapsed_time_ms * 10 ** 6) print("GFLOPs: {:.2f}".format(gflops)) return best_iou, aver_iou, aver_dice, aver_hd, aver_accuracy, aver_recall, aver_precision, aver_f1score, aver_memory, fps, parameters, gflops出现错误 best_iou,aver_iou,aver_dice,aver_hd, aver_accuracy, aver_recall, aver_precision, aver_f1score, aver_memory, FPS, parameters, gflops = val(model,best_iou,val_dataloader) File "D:/BaiduNetdiskDownload/0605_ghostv2unet _tunnelcrack/ghostunet++/UNET++/main.py", line 143, in val return best_iou, aver_iou, aver_dice, aver_hd, aver_accuracy, aver_recall, aver_precision, aver_f1score, aver_memory, fps, parameters, gflops UnboundLocalError: local variable 'gflops' referenced before assignment怎么修改
06-08
这个错误是因为在函数定义了 `gflops` 变量,但是在函数返回时并没有为它赋值,导致出现了未赋值的情况。可以将 `gflops` 变量在函数一开始就赋一个初始值,比如设为0。代码修改如下: ``` def val(model, best_iou, val_dataloader, device): model.eval() aver_iou = 0 aver_dice = 0 aver_hd = 0 aver_accuracy = 0 aver_recall = 0 aver_precision = 0 aver_f1score = 0 aver_memory = 0 fps = 0 parameters = sum(param.numel() for param in model.parameters()) gflops = 0 # 在这里为 gflops 赋一个初始值 with torch.no_grad(): for step, (images, labels) in enumerate(val_dataloader): images = images.to(device) labels = labels.to(device) outputs = model(images) iou, dice, hd, accuracy, recall, precision, f1score = eval_metrics(outputs, labels) memory = torch.cuda.max_memory_allocated() / 1024.0 / 1024.0 aver_iou += iou aver_dice += dice aver_hd += hd aver_accuracy += accuracy aver_recall += recall aver_precision += precision aver_f1score += f1score aver_memory += memory aver_iou /= len(val_dataloader) aver_dice /= len(val_dataloader) aver_hd /= len(val_dataloader) aver_accuracy /= len(val_dataloader) aver_recall /= len(val_dataloader) aver_precision /= len(val_dataloader) aver_f1score /= len(val_dataloader) aver_memory /= len(val_dataloader) fps = len(val_dataloader.dataset) / (time.time() - start_time) # 统计模型的GFLOPs flops = 0 for name, module in model.named_modules(): if isinstance(module, torch.nn.Conv2d): flops += module.weight.numel() * 2 * module.in_channels * module.out_channels * module.kernel_size[0] * module.kernel_size[1] / module.stride[0] / module.stride[1] elif isinstance(module, torch.nn.Linear): flops += module.weight.numel() * 2 * module.in_features start_event = torch.cuda.Event(enable_timing=True) end_event = torch.cuda.Event(enable_timing=True) start_event.record() with torch.no_grad(): output = UNet(args, 3, 1).to(device) end_event.record() torch.cuda.synchronize() elapsed_time_ms = start_event.elapsed_time(end_event) gflops = flops / (elapsed_time_ms * 10 ** 6) print("GFLOPs: {:.2f}".format(gflops)) return best_iou, aver_iou, aver_dice, aver_hd, aver_accuracy, aver_recall, aver_precision, aver_f1score, aver_memory, fps, parameters, gflops ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值