• spring 组件@Scope(request,session)示例


      上回说到, spring组件的注解Scope大约有singleton、prototype、request、session、global session 这么几种常用的场景。今天的示例重点是对request,session两个场景进行一次测试。

      那在谈到具体的示例前,我先分享下对这两种场景的使用心得,以便与各位看官进行思想上的神交! 我们都知道B/S站点运行起来后,是一个多线程的运行环境。每个客户端登录都会产生一个session会话,它的生命周期 从登录系统到 session过期,期间session上存储的信息都是有效可用的,我习惯于叫它会话级的缓存,像用户登录的身份信息我们一般都会绑定到这个session上。这里我们要讲的@Scope("session"),就是spring提供出来的一个会话级bean方案,在这种模式下,用spring的DI功能来获取组件,可以做到在会话的生命周期中这个组件只有一个实例。接下来再说请求(request),http协议的处理模型,从客户端发起request请求,到服务端的处理,最后response给客户端,我们称为一次完整的请求。在这样的一次请求过程中,我们的服务站可能要串行调用funcA->funcB->funcC·... 这样的一串函数,假如我们的系统需要做细致的权限校验(用户权限,数据权限),更可怕的是funcA,funcB,funcC是3个人分别实现的,而且都要做权限校验。那么极有可能会出现3个人各连接了一次数据库,读取了同一批权限数据。这里想象一下,假如一个数据读取要花2秒,那么3个方法就要花费6秒的处理时间。但实际上这些数据只用在这个请求过程中读取一次,缓存在request上下文环境中,我习惯称之为线程级缓存。关于线程级缓存java有ThreadLocal方案,像Hibernate的事务就是用这种方案维持一次执行过程中数据库连接的唯一。当然,今天要讲的@Scope("request")也可以做到这种线程级别的缓存。下面我们看看具体的测试示例

      实现测试步骤说明:

     1、创建一个@Scope("session")标注的Bean组件。关于proxyMode这个参数,是为了解决依存的会话或者请求上下文环境还没有时,自动装载组件报错,这里交给JDK代理,可以保证环境准备就绪时再执行组件装载。

    @Component
    @Scope(value="session")
    public class SessionBean implements ISessionBean {
       private UUID uuid;
       public SessionBean(){
           uuid = UUID.randomUUID();
       }
       public void printId(){
           System.out.println("SessionBean:"+uuid);
       }
    }

     2、创建一个@Scope("request")标注的Bean组件

    @Component
    @Scope(value = "request")
    public class RequestBean implements IRequestBean {
        private UUID uuid;
    
        public RequestBean() {
            uuid = UUID.randomUUID();
        }
    
        public void printId() {
            System.out.println("RequestBean:" + uuid);
        }
    }

    3、添加一个多例的组件自动组装服务类,方便获取session、request组件。

    @Service
    @Scope(value="prototype")
    public class BeanInstance {
        @Autowired
        private IRequestBean requestBean;
        @Autowired
        private ISessionBean sessionBean;
        public IRequestBean getRequestBean() {
            return requestBean;
        }
        public ISessionBean getSessionBean() {
            return sessionBean;
        }
    }

    4、添加测试代码

    @Controller
    @RequestMapping("/user")
    // 添加session信息的注解,可以实现 session信息与map的映射 赋值
    @SessionAttributes("user")
    public class UserController {
        @Autowired
        private BeanInstance beanInstance1;
        @Autowired
        private BeanInstance beanInstance2;
        
        @RequestMapping(value = "/login", method = RequestMethod.GET)
        public String login(String name, Model model, HttpServletRequest request, HttpSession session) {
            model.addAttribute("user", name);
            System.out.println("SessionBean-1");
            beanInstance1.getSessionBean().printId();
            System.out.println("SessionBean-2");
            beanInstance2.getSessionBean().printId();
            System.out.println("RequestBean-1");
            beanInstance1.getRequestBean().printId();
            System.out.println("RequestBean-2");
            beanInstance2.getRequestBean().printId();
            return "user/check";
        }
        /**
         * 检查自动装载的信息
         * @param model
         * @param request
         * @param session
         * @return
         */
        @RequestMapping(value = "/check", method = RequestMethod.GET)
        public String check(Model model, HttpServletRequest request, HttpSession session) {
            System.out.println("SessionBean-1");
            beanInstance1.getSessionBean().printId();
            System.out.println("SessionBean-2");
            beanInstance2.getSessionBean().printId();
            System.out.println("RequestBean-1");
            beanInstance1.getRequestBean().printId();
            System.out.println("RequestBean-2");
            beanInstance2.getRequestBean().printId();
            return "user/check";
        }
    }

    5、先发起一次登录请求,再发起一次登录后的检查请求。从打印的测试结果可以看到两次请求 拿到的session组件,其对应的ID都是相同的,所以在同一个会话中,session组件是唯一的。而request组件,在同一个request请求过程中,调用两次都得到同一个组件ID,而在第二次请求中request组件的ID改变了。因此正如上面所说,@Scope("request")模式在同一请求过程中,spring返回的组件也是唯一的,我们可以用这个方案来做线程级别的数据缓存。

     

    参考资料

    https://www.cnblogs.com/waytofall/p/3460533.html
    https://www.cnblogs.com/lonecloud/p/5937513.html

    每天都是崭新的开始 ——Mr.司满(214382122)[]~( ̄▽ ̄)~*
  • 相关阅读:
    ASP.NET MVC 重点教程一周年版 第二回 UrlRouting
    ASP.NET MVC 重点教程一周年版 第三回 Controller与View
    DynamicData for Asp.net Mvc留言本实例 下篇 更新
    Asp.net MVC视频教程 18 单选与复选框
    使用ASP.NET MVC Futures 中的异步Action
    ASP.NET MVC RC 升级要注意的几点
    ATL、MFC、WTL CString 的今生前世
    msvcprt.lib(MSVCP90.dll) : error LNK2005:已经在libcpmtd.lib(xmutex.obj) 中定义
    关于Windows内存的一些参考文章
    Windows访问令牌相关使用方法
  • 原文地址:https://www.cnblogs.com/MrSi/p/7932218.html
Copyright © 2020-2023  润新知