序列化作用

首先明白一个概念,sessio可以存储在很多位置,并不是固定在某个地方。可能是内存,也可以是硬盘,服务器关闭后,session暂时还不会失效,比如登录页面,如果服务器关闭了,session还没失效,但是开启服务器后,希望还是看到之前登录的用户登录进去的页面,这时候需要序列化改pojo对象,这样pojo对象会跟session一起保存到内存或者硬盘。

而重新开启服务器后,session和pojo会重新被加载,原来的pojo对象也会重新显现出来。所以说session对象的序列化是为了保持对象处于一种状态。

即序列化的作用就是:为了保存在内存中的各种对象的状态(序列化),并且可以把保存的对象状态再读出来(反序列化)。

先简单说下:

应用场景:

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

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

 

(一理解)

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

什么是序列化?

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

什么是反序列化?

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

 

Tomcat下保存的session序列化文件


 

实现了Serializable接口的User类

 

[java]  view plain  copy
 
 在CODE上查看代码片派生到我的代码片
  1. import java.io.Serializable;  
  2.   
  3. public class User implements Serializable {  
  4.   
  5.     private static final long serialVersionUID = 1L;  
  6.     private String username;  
  7.     private String password;  
  8.     public String getUsername() {  
  9.         return username;  
  10.     }  
  11.     public void setUsername(String username) {  
  12.         this.username = username;  
  13.     }  
  14.     public String getPassword() {  
  15.         return password;  
  16.     }  
  17.     public void setPassword(String password) {  
  18.         this.password = password;  
  19.     }  
  20.     @Override  
  21.     public String toString() {  
  22.         return "User [username=" + username + ", password=" + password + "]";  
  23.     }  
  24.     public User() {  
  25.         super();  
  26.     }  
  27.     public User(String username, String password) {  
  28.         super();  
  29.         this.username = username;  
  30.         this.password = password;  
  31.     }  
  32. }  


向session中存放数据的a.jsp

 

 

[java]  view plain  copy
 
 在CODE上查看代码片派生到我的代码片
  1. <%@page import="cn.cil.domain.User"%>  
  2. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>  
  3. <%  
  4. String path = request.getContextPath();  
  5. String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";  
  6. %>  
  7. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
  8. <html>  
  9.   <head>  
  10.     <base href="<%=basePath%>">  
  11.       
  12.     <title>My JSP 'a.jsp' starting page</title>  
  13.       
  14.     <meta http-equiv="pragma" content="no-cache">  
  15.     <meta http-equiv="cache-control" content="no-cache">  
  16.     <meta http-equiv="expires" content="0">      
  17.     <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">  
  18.     <meta http-equiv="description" content="This is my page">  
  19.   
  20.   </head>  
  21.     
  22.   <body>  
  23.     <h1>向 Session 存放资源</h1>  
  24.     <%  
  25.         User user = new User("123","abc");  
  26.         session.setAttribute("user",user);  
  27.     %>  
  28.   </body>  
  29. </html>  
  30. </strong></span>  

取数据的b.jsp

 

 

[java]  view plain  copy
 
 在CODE上查看代码片派生到我的代码片
  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>  
  2. <%  
  3. String path = request.getContextPath();  
  4. String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";  
  5. %>  
  6.   
  7. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
  8. <html>  
  9.   <head>  
  10.     <base href="<%=basePath%>">  
  11.       
  12.     <title>My JSP 'b.jsp' starting page</title>  
  13.       
  14.     <meta http-equiv="pragma" content="no-cache">  
  15.     <meta http-equiv="cache-control" content="no-cache">  
  16.     <meta http-equiv="expires" content="0">      
  17.     <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">  
  18.     <meta http-equiv="description" content="This is my page">  
  19.   
  20.   </head>  
  21.     
  22.   <body>  
  23.     <h1>从 Seesion 中取资源</h1>  
  24.     <%= session.getAttribute("user") %>  
  25.   </body>  
  26. </html>  
  27. </strong></span>  


 

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

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


模拟对象的序列化反序列化

 

[java]  view plain  copy
 
 在CODE上查看代码片派生到我的代码片
  1. import java.io.File;  
  2. import java.io.FileInputStream;  
  3. import java.io.FileOutputStream;  
  4. import java.io.ObjectInputStream;  
  5. import java.io.ObjectOutputStream;  
  6.   
  7. import org.junit.Test;  
  8.   
  9. import cn.cil.domain.User;  
  10.   
  11.   
  12. public class TestSerializable {  
  13.   
  14.     @Test  
  15.     public void test() throws Exception {  
  16.           
  17.         User user = new User("123","abc");  
  18.         SerializeObj(user);  
  19.         User users = ObjDeSerialize();  
  20.         System.out.println(users);  
  21.     }  
  22.       
  23.     private void SerializeObj(User user) throws Exception{  
  24.           
  25.         ObjectOutputStream outObj = new ObjectOutputStream(  
  26.                 new FileOutputStream(new File("G:/SESSIONS.ser")));  
  27.         outObj.writeObject(user);  
  28.         System.out.println("对象序列化完成");  
  29.     }  
  30.       
  31.     private User ObjDeSerialize() throws Exception{  
  32.         ObjectInputStream inObj = new ObjectInputStream(new FileInputStream(  
  33.                 new File("G:/SESSIONS.ser")));  
  34.         User user = (User)inObj.readObject();  
  35.         System.out.println("对象反序列化完成");  
  36.         return user;  
  37.     }  
  38.   
  39. }  



 

特别注意:

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

 

 

[java]  view plain  copy
 
 在CODE上查看代码片派生到我的代码片
  1. public class User implements Serializable{   
  2.   
  3.     //private static final long serialVersionUID = 1L; //不添加ID  
  4.     private String username;  
  5.     private String password;  
  6.     //private int age = 10; 对象序列化后,新增内容  
  7.       
  8.     public String getUsername() {  
  9.         return username;  
  10.     }  
  11.     public void setUsername(String username) {  
  12.         this.username = username;  
  13.     }  
  14.     public String getPassword() {  
  15.         return password;  
  16.     }  
  17.     public void setPassword(String password) {  
  18.         this.password = password;  
  19.     }  
  20.       
  21.   
  22.       
  23.     /*@Override 
  24.     public String toString() { 
  25.         return "User [username=" + username + ", password=" + password 
  26.                 + ", age=" + age + "]"; 
  27.     }*/  
  28.       
  29.     /*@Override 
  30.     public String toString() { 
  31.         return "User [username=" + username + ", password=" + password 
  32.                 + "]"; 
  33.     }*/  
  34.     public User() {  
  35.         super();  
  36.     }  
  37.     public User(String username, String password) {  
  38.         super();  
  39.         this.username = username;  
  40.         this.password = password;  
  41.     }  
  42. }  
  43.   
  44.   
  45. @Test  
  46.     public void test2() throws Exception {  
  47.           
  48.         User user = new User("123","abc");  
  49.           
  50.         SerializeObj(user);  
  51.           
  52.     }  
  53.     @Test  
  54.     public void test3() throws Exception {  
  55.           
  56.         User users = ObjDeSerialize();  
  57.         System.out.println(users);  
  58.           
  59.     }  
  60. </strong></span>  


在反序列化前,打开注释部分,进行反序列化

 


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

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

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


二、session的活化和钝化

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

 

将下面配置文件放到tomcat\conf\catalina\localhost目录下!文件名称为项目名称。

[html]  view plain  copy
 
 在CODE上查看代码片派生到我的代码片
  1. <Context>  
  2.     <Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1"[如果session在1分钟内没有使用,那么Tomcat就会钝化它]>  
  3.         <Store className="org.apache.catalina.session.FileStore" directory="mysession"[把session序列化到Tomcat\work\Catalina\localhost\listener\mysession目录下。]/>  
  4.     </Manager>  
  5. </Context>  

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

 

 

 

session数据

(二理解)

序列化是什么?

简单说就是为了保存在内存中的各种对象的状态,并且可以把保存的对象状态再读出来。虽然你可以用你自己的各种各样的方法来保存Object States,但是Java给你提供一种应该比你自己好的保存对象状态的机制,那就是序列化。

2、什么情况下需要序列化 

a)当你想把的内存中的对象保存到一个文件中或者数据库中时候;
b)当你想用套接字在网络上传送对象的时候;
c)当你想通过RMI传输对象的时候;

3、当对一个对象实现序列化时,究竟发生了什么?

在没有序列化前,每个保存在堆(Heap)中的对象都有相应的状态(state),即实例变量(instance ariable)比如:

Foo myFoo = new Foo(); 
myFoo .setWidth(37); 
myFoo.setHeight(70); 

  当通过下面的代码序列化之后,MyFoo对象中的width和Height实例变量的值(37,70)都被保存到foo.ser文件中,这样以后又可以把它 从文件中读出来,重新在堆中创建原来的对象。当然保存时候不仅仅是保存对象的实例变量的值,JVM还要保存一些小量信息,比如类的类型等以便恢复原来的对 象。
服务器重启后,要想得到session的原来对象的的方法:

    众所周知,session是服务器端的一种会话技术,只要session没有关闭,一个会话就会保持。这里先引出一个问题:如果我在访问某个页面后,服务器重启了一下,但是网页还没关,那么原来的session还在么?答案是很明显的,你都把服务器关掉了,session肯定不是原来的session了,原来的像登录信息等一些跟session相关的信息肯定就没了。但是如果我们想要服务器重启后,还是原来的session,那跟如何做呢?

我们看下session的存储方式:

1.1保存在IIS进程中:

  保存在IIS进程中是指把Session数据保存在IIS的运行的进程中,也就是inetinfo.exe这个进程中,这也是默认的Session的存方式,也是最常用的。

  这种方式的优点是简单,性能最高。但是当重启IIS服务器时Session丢失。

 

  1.2.保存在StateServer上

  这种存储模式是指将Session数据存储在一个称为Asp.Net状态服务进程中,该进程独立于Asp.Net辅助进程或IIS应用程序池的单独进程,使用此模式可以确保在重新启动Web应用程序时保留会话状态,并使会话状态可以用于网络中的多个Web服务器。可以通过序列化到内存中,保存session对象。

序列化是将内存中的二进制取出来,session数据存储在内存中,如果实现序列化的话,可以读取出来,即关闭服务器后开了之后还可以获取到原来的session对象。

 

  1.3.保存在SQL Server数据库中

  可以配置把Session数据存储到SQL Server数据库中,为了进行这样的配置,程序员首先需要准备SQL Server数据服务器,然后在运行.NET自带安装工具安装状态数据库。

  这种方式在服务器挂掉重启后都还在,因为他存储在内存和磁盘中。

 

        这就涉及到了一个叫序列化(Serializable)的技术。当对象存储到硬盘的时候,就需要实现序列化接口,序列化的功能就是添加了一个唯一的ID(类主键),这样在反序列化(从硬盘加载到内存)的时候就可以成功找到相应的对象。另外,还要弄清楚一件事情:一般大家都觉得容器关闭后,session就销毁了,其实不是这样的,容器的关闭并不会导致session的销毁。过程是这样子的,一旦容器关闭后,session就会被持久化到硬盘,并没有真正销毁,为了说明这个问题,来做个试验:打开tomcat的工作目录下正在运行的工程目录:我的是E:\web\apache-tomcat-8.0.26\work\Catalina\localhost\E_shop,里面只有一个org的文件夹,其他什么也没有,现在我们重启tomcat服务器,注意观察这里面的变化,当服务器停掉后,这个该目录下多了个SESSION.ser文件,服务器重启成功后,该文件又消失了。如下:

        所以,如果项目中的POJO实现了Serializable接口,当反序列化的时候就能找到刚刚序列化时候的POJO,原来session中的内容就能成功反序列化,session还是原来的session,这样原来页面的东西还在,刷新后还是继续上次的操作。如果POJO没有被实例化,那么在session发序列化的时候当然就没有了这些POJO了。下面看一下我的项目中的部分POJO,如下:

        最后总结一下:

        1. 容器关闭后session并没有消失,而是被持久化到了硬盘里;

        2. 如果项目中的POJO实现了Serializable接口,那么会跟着session一起被持久化到硬盘,在反序列化的时候会成功还原;

        3. 要想服务器重启后,还是原来的session,还继续紧接着原来的页面操作的话,就需要序列化项目中的POJO。



6、相关注意事项

a)当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;
b)当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;
c)并非所有的对象都可以序列化,,至于为什么不可以,有很多原因了,比如:

  1.安全方面的原因,比如一个对象拥有private,public等field,对于一个要传输的对象,比如写到文件,或者进行rmi传输 等等,在序列化进行传输的过程中,这个对象的private等域是不受保护的。
  2. 资源分配方面的原因,比如socket,thread类,如果可以序列化,进行传输或者保存,也无法对他们进行重新的资源分 配,而且,也是没有必要这样实现。

 

因为session是用来传输各种值和对象的 而对象不能通过网络直接传输 所以必须序列化,

如果不序列化的话,可能导致网络中传输失败.

序列化的方法很简单,只要实现Java.io.serialia就可以了,并且加上唯一标识即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值