Session经常被大家翻译为【会话】,在一个应用内部设计架构中,它通常指进程内保存的状态数据或者属性。
2007年
2007年我的本科毕业设计里,用了很多JSP里嵌Java代码的操作。比如登录是这么写的:
运行效果是这样的:
对的,我就是用这么原始的技术成功的混到了毕业文凭。
我周围的男同学技术比我要好一些,他们的用法也比我要高级,前端JSP里没有调用Java代码,有专门的后端来处理。
HttpSession hs = request.getSession();
PrintWriter pw = response.getWriter();
String msg = request.getParameter("ming");
pw.println(msg);
pw.println(hs.getId());
这两种方式本质上就是使用Java Servlet配合http协议标准来实现的。
HttpSession
服务器会为每一个用户 创建一个独立的HttpSession
原理
当用户第一次访问Servlet时,服务器端会给用户创建一个独立的Session
并且生成一个SessionID,这个SessionID在响应浏览器的时候会被装进cookie中,从而被保存到浏览器中
当用户再一次访问Servlet时,请求中会携带着cookie中的SessionID去访问
对于Servlet而言。服务器会根据这个SessionID去查看是否有对应的Session对象,有就拿出来使用;没有就创建一个Session(相当于用户第一次访问)。换句话说:若Servlet是客户端访问的第一个WEB应用的资源,则只有调用了request.getSession()或request.getSession(true) 才会创建HttpSession对象。
域的范围
Context域 > Session域 > Request域
Session域 只要会话不结束就会存在 但是Session有默认的存活时间(30分钟)
注意点
1>这时候的Session是跨线程的。
2>一个Session的概念需要包括特定的客户端,特定的服务器端以及不中断的操作时间。A用户和C服务器建立连接时所处的Session同B用户和C服务器建立连接时所处的Session是两个不同的Session。基于这个注意点,多数线上服务都是采用集群或者在扩展性上支持了集群,所以现在基本上没有人使用HttpSession了,当然只是做个毕设还是可以的。
总结
通过HttpSession主要是获取其中保存的状态数据或者属性,是一种状态的保持。
2015年
2015年我做了一个PHP的项目,发现在PHP里Session那个好用。其实PHP里的Session和Java Servlet的Session原理基本相同。在集群情况下也是会失效的。但是为什么都过去8年了,Java中基本已经淘汰了这种用法,在PHP里还在用呢?
我个人理解那就是PHP语言的本身适用范围了。PHP本身适用于简单轻量的小型系统,这种系统有些就是单服务器在运行的。对可用性要求也不是特别高,出了问题可以通过立即重启或者启用备份服务器解决。Session里的信息如用户信息丢了用户重新登录就好了。
总结
通过PHP里Session和HttpSession一样,主要是获取其中保存的状态数据或者属性,是一种状态的保持。
2016年
当时做项目用到ActiveMQ,它实现了JMS标准。先看一段简单代码:
public class JMSProducer {
public static void main(String[] args) {
//连接工厂
ConnectionFactory connectionFactory;
//连接
Connection connection = null;
//会话,接受或者发送消息的线程
Session session;
//消息的目的地
Destination destination;
//消息生产者
MessageProducer messageProducer;
//实例化工厂
connectionFactory = new ActiveMQConnectionFactory(ConnectionConstants.BROKENURL);
try {
//获取连接
connection = connectionFactory.createConnection(ConnectionConstants.USERNAME, ConnectionConstants.PASSWORD);
//启动连接
connection.start();
//创建session
//参数1:1、true:支持事务
//为true时:paramB的值忽略, acknowledgment mode被jms服务器设置为SESSION_TRANSACTED 。
// 2、false:不支持事务
// 为false时:paramB的值可为Session.AUTO_ACKNOWLEDGE、Session.CLIENT_ACKNOWLEDGE、DUPS_OK_ACKNOWLEDGE其中一个,
// 为Session.SESSION_TRANSACTED时会报错!
//参数2:Session.AUTO_ACKNOWLEDGE为自动确认,客户端发送和接收消息不需要做额外的工作。异常也会确认消息,应该是在执行之前确认的
//Session.CLIENT_ACKNOWLEDGE为客户端确认。客户端接收到消息后,必须调用javax.jms.Message的acknowledge方法。jms服务器才会删除消息。可以在失败的
//时候不确认消息,不确认的话不会移出队列,一直存在,下次启动继续接受。接收消息的连接不断开,其他的消费者也不会接受(正常情况下队列模式不存在其他消费者)
//DUPS_OK_ACKNOWLEDGE允许副本的确认模式。一旦接收方应用程序的方法调用从处理消息处返回,会话对象就会确认消息的接收;而且允许重复确认。在需要考虑资源使用时,这种模式非常有效。
session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
//创建一个消息队列
destination = session.createQueue("firstDemo");
//创建消息生成这
messageProducer = session.createProducer(destination);
//创建消息
TextMessage message = session.createTextMessage("ACTIVEMQ 生产者 生产消息,这是第"+i+"次生产");
//发出消息
messageProducer.send(message);
session.commit();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
注意在上面的connection连接中创建了session。在《深入理解MQ生产端的底层通信过程-理解channel》的MQ中怎么使用Channel那一节,RabbitMQ的生产端 connection.createChannel()。对比之下,情不自禁就要问了,这里的Channel等价于Session?
自然不是啦,针对他们的区别。知乎上有个神回复:“Session是会话,比如打电话,从拨号到挂断这就是一个Session;Channel是通道,我的理解是比如打电话时,Channel表示是使用联通信号或者是移动信号或者是电信信号。”
Channel是文件的读取等操作的抽象,而Session我理解是连接中状态数据的保持或者复用。Channel在《深入理解MQ生产端的底层通信过程-理解channel》里讲过了。那Session这块怎么理解呢?
在上面JMSProducer的代码中,我可写了大段的注释。这些注释可不是白写的。我们列举一下在上面的Session中显式的保存了哪些东西:
是否支持事务
客户端收到消息是否自动确认
一个消息队列firstDemo
一个可以发消息给firstDemo的生产者
一个消息内容
一般我们每次发消息时,消息内容会需要新建,但是生产者、消息队列、是否支持事务和客户端收到消息是否自动确认这些都可以复用。幸好人家设计的时候也设计了Session,每次直接用就可以了。
总结:MQ中的Session是连接中状态数据的保持或者复用
2020年
项目原因我研究了mybatis的源码,本来都计划为了满足项目需求自己重写一个mybatis了,后来重新规划设计没有做。在《mybatis的本质和原理》里我手撕了一个简易mybatis,里面有提到SqlSession。作用类似于一个 JDBC 中的 Connection 对象的代理,代表着一个连接资源的启用,它的作用有 3 个:
获取 Mapper 接口。
发送 SQL 给数据库。
控制数据库事务。
本质上我理解也是连接中状态数据的保持或者复用。一段代码感受一下:
//定义 SqlSession
SqlSession sqlSession = null;
try {
// 打开 SqlSession 会话
sqlSession = SqlSessionFactory.openSession();
// some code...
sqlSession.commit(); // 提交事务
} catch (IOException e) {
sqlSession.rollback(); // 回滚事务
}finally{
// 在 finally 语句中确保资源被顺利关闭
if(sqlSession != null){
sqlSession.close();
}
}
上面在sqlSession对象中进行了事务的提交和回滚操作,非常类似于咱们在navicate等mysql客户端界面上的一个会话终端的操作。
在这同一个session下,因为就好像之前在HttpSession 登录有效期内用户的操作一样,只是界面不同。
总结
本文从个人的时间经历,分析了Session演进的血缘关系。这十几年的演进中,Session的概念越来越泛化,但是本质上还是保存的状态数据或者属性。
联系客服