zoukankan      html  css  js  c++  java
  • 【转】JavaWeb之Session的序列化和反序列化 && Session的活化和钝化

    应用场景:

    1.一般来说,服务器启动后,就不会再关闭了,但是如果逼不得已需要重启,而用户会话还在进行相应的操作,这时就需要使用序列化将session信息保存起来放在硬盘,服务器重启后,又重新加载。这样就保证了用户信息不会丢失,实现永久化保存

    2.淘宝每年都会有定时抢购的活动,很多用户会提前登录等待,长时间不进行操作,一致保存在内存中,而到达指定时刻,几十万用户并发访问,就可能会有几十万个session,内存可能吃不消,这时就需要进行对象的活化、钝化,让其在闲置的时候离开内存,将信息保存至硬盘,等要用的时候,就重新加载进内存


    一、session的序列化和反序列化

    什么是序列化?

    把对象的状态信息转换为可以存储或传输的形式过程,简单说就是把对象转换为字节形式存储的过程称为对象的序列化

    什么是反序列化?

    把字节序列转化为对象的过程


    Tomcat下保存的session序列化文件



    实现了Serializable接口的User类

    import java.io.Serializable;  
      
    public class User implements Serializable {  
      
        private static final long serialVersionUID = 1L;  
        private String username;  
        private String password;  
        public String getUsername() {  
            return username;  
        }  
        public void setUsername(String username) {  
            this.username = username;  
        }  
        public String getPassword() {  
            return password;  
        }  
        public void setPassword(String password) {  
            this.password = password;  
        }  
        @Override  
        public String toString() {  
            return "User [username=" + username + ", password=" + password + "]";  
        }  
        public User() {  
            super();  
        }  
        public User(String username, String password) {  
            super();  
            this.username = username;  
            this.password = password;  
        }  
    }  
    向session中存放数据的a.jsp
    <%@page import="cn.cil.domain.User"%>  
    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>  
    <%  
    String path = request.getContextPath();  
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";  
    %>  
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
    <html>  
      <head>  
        <base href="<%=basePath%>">  
          
        <title>My JSP 'a.jsp' starting page</title>  
          
        <meta http-equiv="pragma" content="no-cache">  
        <meta http-equiv="cache-control" content="no-cache">  
        <meta http-equiv="expires" content="0">      
        <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">  
        <meta http-equiv="description" content="This is my page">  
      
      </head>  
        
      <body>  
        <h1>向 Session 存放资源</h1>  
        <%  
            User user = new User("123","abc");  
            session.setAttribute("user",user);  
        %>  
      </body>  
    </html>  
    </strong></span>  
    取数据的b.jspw plain cop
    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>  
    <%  
    String path = request.getContextPath();  
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";  
    %>  
      
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
    <html>  
      <head>  
        <base href="<%=basePath%>">  
          
        <title>My JSP 'b.jsp' starting page</title>  
          
        <meta http-equiv="pragma" content="no-cache">  
        <meta http-equiv="cache-control" content="no-cache">  
        <meta http-equiv="expires" content="0">      
        <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">  
        <meta http-equiv="description" content="This is my page">  
      
      </head>  
        
      <body>  
        <h1>从 Seesion 中取资源</h1>  
        <%= session.getAttribute("user") %>  
      </body>  
    </html>  
    </strong></span>  

    在向seesion保存资源后(访问a.jsp后),关闭tomcat,然后迅速打开tomcat的work目录到指定项目文件中,就会看到生成的Sessions.ser文件,这个文件保存的就是所有session对象序列化后的信息

    这时,再重启Tomcat,会看到SESSIONS.ser文件消失,又被重新加载,再访问b.jsp,原来的对象信息还在


    模拟对象的序列化反序列化
    import java.io.File;  
    import java.io.FileInputStream;  
    import java.io.FileOutputStream;  
    import java.io.ObjectInputStream;  
    import java.io.ObjectOutputStream;  
      
    import org.junit.Test;  
      
    import cn.cil.domain.User;  
      
      
    public class TestSerializable {  
      
        @Test  
        public void test() throws Exception {  
              
            User user = new User("123","abc");  
            SerializeObj(user);  
            User users = ObjDeSerialize();  
            System.out.println(users);  
        }  
          
        private void SerializeObj(User user) throws Exception{  
              
            ObjectOutputStream outObj = new ObjectOutputStream(  
                    new FileOutputStream(new File("G:/SESSIONS.ser")));  
            outObj.writeObject(user);  
            System.out.println("对象序列化完成");  
        }  
          
        private User ObjDeSerialize() throws Exception{  
            ObjectInputStream inObj = new ObjectInputStream(new FileInputStream(  
                    new File("G:/SESSIONS.ser")));  
            User user = (User)inObj.readObject();  
            System.out.println("对象反序列化完成");  
            return user;  
        }  
      
    }  
     

     

    特别注意:

    1.进行对象的序列化和反序列化的对象,必须实现Serializable接口,否则无法进行序列化和反序列化,当然这仅仅可以进行序列化和反序列化而已,如果序列化完成的对象(已经保存至硬盘),反序列化前又修改了对象,那么反序列化会失败,所以进行序列化的对象必须还要添加serialVersionUID

    public class User implements Serializable{   
      
        //private static final long serialVersionUID = 1L; //不添加ID  
        private String username;  
        private String password;  
        //private int age = 10; 对象序列化后,新增内容  
          
        public String getUsername() {  
            return username;  
        }  
        public void setUsername(String username) {  
            this.username = username;  
        }  
        public String getPassword() {  
            return password;  
        }  
        public void setPassword(String password) {  
            this.password = password;  
        }  
          
      
          
        /*@Override 
        public String toString() { 
            return "User [username=" + username + ", password=" + password 
                    + ", age=" + age + "]"; 
        }*/  
          
        /*@Override 
        public String toString() { 
            return "User [username=" + username + ", password=" + password 
                    + "]"; 
        }*/  
        public User() {  
            super();  
        }  
        public User(String username, String password) {  
            super();  
            this.username = username;  
            this.password = password;  
        }  
    }  
      
      
    @Test  
        public void test2() throws Exception {  
              
            User user = new User("123","abc");  
              
            SerializeObj(user);  
              
        }  
        @Test  
        public void test3() throws Exception {  
              
            User users = ObjDeSerialize();  
            System.out.println(users);  
              
        }  
    </strong></span>  
    在反序列化前,打开注释部分,进行反序列化


    这也就说明了,文件流中的class和web下的classpath中的class(修改后)不一致了,会抛出异常,所以进行序列化的对象,如果需要在修改后还可以进行反序列化,就必须添加serialVersionUID,如果不指定serialVersionUID,Java编译器会自动帮我们添加,一个对象只要修改一点点,他们的serialVersionUID就会不一致,序列化前是一个serialVersionUID,反序列化又是一个serialVersionUID,两个serialVersionUID不一致,肯定会异常。Eclipse如此强大,不填写serialVersionUID时,它会报警。所以稍稍注意一下。

    2.如果一个对象不实现Serializable接口,它是无法进行序列化的,根本就无法转换为字节序列

    实现Serializable接口,就好比坐飞机的机票,有机票带你飞,没票在地上呆着


    二、session的活化和钝化

    当一个用户长时间不进行操作的时,服务器为减轻内存压力,可以将其session保存到硬盘中,等待用户再次操作的时候,再从硬盘中取出来,(保存到硬盘中的信息不会删除)

    将下面配置文件放到tomcatconfcatalinalocalhost目录下!文件名称为项目名称。

    <Context>  
        <Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1"[如果session在1分钟内没有使用,那么Tomcat就会钝化它]>  
            <Store className="org.apache.catalina.session.FileStore" directory="mysession"[把session序列化到TomcatworkCatalinalocalhostlistenermysession目录下。]/>  
        </Manager>  
    </Context>  

    w plain

    当然也可以放到tomcat的config下的context.xml中,这样就是对Tomcat下所有应用都生效

  • 相关阅读:
    CentOS5.5环境下布署LVS+keepalived
    CentOS 6.3下部署LVS(NAT)+keepalived实现高性能高可用负载均衡
    Redis的事务
    Redis_持久化之RDB
    Redis有序集合Zset(sorted set)
    Redis哈希-hash
    Redis集合-Set
    Redis 数据类型-List
    Java多线程与并发库高级应用-同步集合
    Java多线程与并发库高级应用-可阻塞的队列
  • 原文地址:https://www.cnblogs.com/yft-javaNotes/p/10520196.html
Copyright © 2011-2022 走看看