以上就是给各位分享运行中的hessian对象临时变化,同时本文还将给你拓展Cookie对象与Session对象-java、dubbo服务中的hessian序列化工厂使用hashmap加锁在高并发场景下
以上就是给各位分享运行中的hessian对象临时变化,同时本文还将给你拓展Cookie对象与Session对象-java、dubbo服务中的hessian序列化工厂使用hashmap加锁在高并发场景下的问题、Grails通过sessionId获取session对象、Hessian等相关知识,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!
本文目录一览:- 运行中的hessian对象临时变化
- Cookie对象与Session对象-java
- dubbo服务中的hessian序列化工厂使用hashmap加锁在高并发场景下的问题
- Grails通过sessionId获取session对象
- Hessian
运行中的hessian对象临时变化
J2EE中和安卓之间的通信,使用hessian来解决会快很多,对开发来说也会方便很多,直接可以传输对象。但是如果web端对bean对象进行了升级,而安卓的apk升级时间跨度会比较长,如此一来就需要研究测试一下这种情况下接口是否还能正常运行。
增加一个属性
首先,传输一个对象需要实现Serializable接口,接着我们在服务器上增加一个属性,并在接口中赋值传输回去。
结果客户端正常调用,因为客户端使用的是旧bean对象,所以也不会使用到这个属性,没有任何影响。
删除一个属性
接着我们测试删除一个属性。这个时候客户端依旧能够调用成功,在代码上不存在任何问题,但由于缺少属性,逻辑上可能会有问题。
修改一个属性的类型
我们先将一个string属性修改成integer属性,测试发现没有任何问题,在服务器上的一个integer成功转成了客户端上的string类型。
也许这样还不够,我们将服务器端的一个intger改成string试试,此时接口调用会出现一个错误,无法把integer转成string类型(即使服务器传输的是一个数字字符串)。
Cookie对象与Session对象-java
1.Cookie对象
1.1常见的方法
(1)创建Cookie对象,绑定数据
new Cookie(String name, String value)
(2)发送Cookie对象
response.addCookie(Cookie cookie)
(3)获取Cookie,拿到数据
Cookie[] request.getCookies()
示例:
@WebServlet("/cookieDemo")
public class CookieDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取Cookie
Cookie[] cs = req.getCookies();
// 遍历Cookies[]
if (cs != null){
for (Cookie c : cs) {
String name = c.getName();
String value = c.getValue();
System.out.println(name + ":" + value);
}
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}
1.2Cookie的实现原理
基于响应头set-cookie和请求头cookie实现
1.3Cookie的细节
(1)一次可不可以发送多个cookie?
可以。可以创建多个Cookie对象,使用response调用多次addCookie方法发送cookie即可。
(2)cookie在浏览器中保存多长时间?
默认情况下,当浏览器关闭后,Cookie数据被销毁(保存在浏览器内存)。但是我们可以设置cookie的保存时间(持久化到硬盘)。具体方法:
setMaxAge(int seconds)
1. 正数:将Cookie数据写到硬盘的文件中。持久化存储。并指定cookie存活时间,时间到后,cookie文件自动失效
2. 负数:默认值
3. 零:删除cookie信息
(3)cookie能不能存中文?
在tomcat 8 之前 cookie中不能直接存储中文数据,需要将中文数据转码---一般采用URL编码。
在tomcat 8 之后,cookie支持中文数据。特殊字符还是不支持,建议使用URL编码存储,URL解码解析
(4)假设在一个tomcat服务器中,部署了多个web项目,那么在这些web项目中cookie能不能共享?
默认情况下不可以。但是可以设置。setPath(String path):设置cookie的获取范围。默认情况下是设置为当前的虚拟目录。如果要共享,则可以将path设置为"/"。
(5)不同的tomcat服务器间cookie共享问题?
setDomain(String path):如果设置一级域名相同,那么多个服务器之间cookie可以共享。
例如:
setDomain(".baidu.com"),那么tieba.baidu.com和news.baidu.com中cookie可以共享
2.HttpSession对象
2.1常见的方法
(1)获取HttpSession对象
HttpSession session = request.getSession();
(2)使用HttpSession对象
Object getAttribute(String name)
void setAttribute(String name, Object value)
void removeAttribute(String name)
2.2实现原理
Session的实现是依赖于Cookie的。
刚开始没有Session对象时,HttpSession session = request.getSession();拿不到Session对象,此时服务端会自动创建一个Cookie对象,new Cookie(“JSESSIONID”, [这里是session的id])。并发送Cookie对象给客户端。response.addCookie(Cookie cookie)。这时候request.getSession()就可以拿到Session的id了,然后根据id查询出Session对象。
如果本来客户端的Cookie就有Session的id。就直接获取到id并查询获取到Session对象了。
2.3HttpSession的细节
(1)当客户端关闭后,服务器不关闭,两次获取session是否为同一个?
默认情况下不是,因为Cookie一关闭浏览器就删除了。第二次再请求服务器,服务器如果要获取Session对象,就会再创建一个新的Session对象了。
但是我们可以设置Cookie的存活时间,来保证cookie重启了浏览器后还存在。
Cookie c = new Cookie("JSESSIONID",session.getId());
c.setMaxAge(60*60);
response.addCookie(c);
(2)客户端不关闭,服务器关闭后,两次获取的session是同一个吗?
很明显的,不是同一个。
但是如果服务器重启,丢失了原来的Session,是一件很惨的事情。比如你是一个商城应用,未登录的用户的购物车信息都存在服务器的Session对象里。突然你丢失了,用户的购物车数据全都不见了。有什么解决办法呢?
session的钝化:在服务器正常关闭之前,将session对象系列化到硬盘上
session的活化:在服务器启动后,将session文件转化为内存中的session对象即可。
如果我们的应用部署在Tomcat的webapps上,Tomcat服务器已经帮我们做好了session的钝化和活化了。但是在IDEA里面只有钝化,没有活化。(这里不细说了,感兴趣的自己了解下)。还有一个条件,必须是Tomcat正常关闭的前提下。所以还是自己做一下session的钝化和活化为好。具体就是把对象序列化到一个文件。
(3)session什么时候被销毁?
1. 服务器关闭
2. session对象调用invalidate() 。
3. session默认失效时间 30分钟(就算开着浏览器,30分钟没有操作Session,服务器也会自动销毁)
选择性配置修改
<session-config>
<session-timeout>30</session-timeout>
</session-config>
2.4session的特点
1. session用于存储一次会话的多次请求的数据,存在服务器端
2. session可以存储任意类型,任意大小的数据
2.5Session与Cookie的区别?
1. session存储数据在服务器端,Cookie在客户端
2. session没有数据大小限制,Cookie有
3. session数据安全,Cookie相对于不安全
dubbo服务中的hessian序列化工厂使用hashmap加锁在高并发场景下的问题
1.问题描述
我们在对5个dubbo接口并发进行测试,总共线程数是64个,不停的调用这些接口。观察到的异常显现是TPS波动较大,时高时低。
我们观察线程的运行状况是这样的:
上图红色部分是线程阻塞的情况。
我们查看线程栈的信息发现有20多个用户线程处于Blocked状态,blocked状态的代码如下:
"DubboServerHandler-192.168.183.17:20880-thread-200" daemon prio=10 tid=0x00007fc0e802b800 nid=0x6a8f waiting for monitor entry [0x00007fbf25bda000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.jd.com.caucho.hessian.io.SerializerFactory.getSerializer(SerializerFactory.java:164)
- locked <0x00000000c35af008> (a java.util.HashMap)
at com.alibaba.com.caucho.hessian.io.Hessian2Output.writeObject(Hessian2Output.java:406)
at com.
alibaba.com.caucho.hessian.io.CollectionSerializer.writeObject(CollectionSerializer.java:102)
at com.
alibaba.com.caucho.hessian.io.Hessian2Output.writeObject(Hessian2Output.java:408)
at com.
alibaba.com.caucho.hessian.io.JavaSerializer$FieldSerializer.serialize(JavaSerializer.java:313)
|
这说明如果该服务在该并发下还是会出现用户线程阻塞在代码
at com.alibaba.com.caucho.hessian.io.SerializerFactory.getSerializer(SerializerFactory.java:164)处的情况,对于服务的稳定性和TPS都会造成一定的影响。
2.问题分析
根据上述日志的分析,我们定位到了线程锁部分的代码,我们打开该代码如下所示:
if (_cachedSerializerMap != null) {
synchronized (_cachedSerializerMap) {
serializer = (Serializer) _cachedSerializerMap.get(cl);
}
|
可以看到此处使用了HashMap,在并发读写map的代码的地方都添加了synchronized 关键字。而本问题也就是在该处BLOCKED了。如果并发较大的时候,线程释放锁的速度赶不上线程争夺资源的速度就会导致用户线程的锁定。
3.优化方案
在高并发的场景下,Hashmap+synchronized的锁的粒度太大,直接锁定了整个HashMap对象,那么我们可以用 ConcurrentHashMap来降低锁的粒度,这样并发处理能力就能够增强。
我在搜索类SerializerFactory的时候,也正好搜索到了hessian-4.0.7.jar中也有这个类,应该是dubbo从hessian里移植过来的另一个类。在这个版本里它就将HashMap替换为ConcurrentHashMap,
它替换之后的代码是这样的:
private ConcurrentHashMap _cachedSerializerMap;
private ConcurrentHashMap _cachedDeserializerMap;
Serializer serializer;
if (_cachedSerializerMap != null) {
serializer = (Serializer) _cachedSerializerMap.get(cl);
if (serializer != null)
return serializer;
}
|
它的区别就是使用ConcurrentHashMap ,去除了synchronized 关键字。
接下来我们也做这样的修改,替换jar包之后,再对服务进行一次压测,结果如下:
1.线程中无Blocked状态的用户线程。
2.TPS更加稳定。
TPS变得更加稳定,没有较大的波动。
从测试来看这种优化之后是有实际效果的,dubbo服务的并发能力明显增强了许多。
总结:
对于并发较高的dubbo服务,若希望提高并发处理能力,则应该做这样的优化。
Grails通过sessionId获取session对象
Grails通过sessionId获取session对象
思路:自定义一个类用来监听
session
,所有session
存入map
中,sessionId
作为读取的key
创建监听类 SessionTracker
package com.session
import org.springframework.beans.BeansException
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware
import org.springframework.web.context.WebApplicationContext
import javax.servlet.http.HttpSession
import javax.servlet.http.HttpSessionEvent
import javax.servlet.http.HttpSessionListener
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentMap
class SessionTracker implements HttpSessionListener, ApplicationContextAware {
private static final ConcurrentMap<String, HttpSession> sessions = new ConcurrentHashMap<String, HttpSession>();
void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
def servletContext = ((WebApplicationContext) applicationContext).getServletContext()
servletContext.addListener(this);
}
void sessionCreated(HttpSessionEvent httpSessionEvent) {
sessions.putAt(httpSessionEvent.session.id, httpSessionEvent.session)
}
void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
sessions.remove(httpSessionEvent.session.id)
}
HttpSession getSessionById(id) {
sessions.get(id)
}
}
在 grails-app/conf/resoures.groovy
中注册
import com.session.SessionTracker
// Place your Spring DSL code here
beans = {
// 自定义session监听器
sessionTracker(SessionTracker)
}
获取session
package com.genee
import org.springframework.web.context.request.RequestContextHolder
import javax.servlet.http.HttpSession
class HiController {
// 注入监听对象
def sessionTracker
def index() {
// 获取session
def sessionId = RequestContextHolder.currentRequestAttributes().getSessionId()
println "原sessionId:$sessionId"
// 根据sessionId获取session对象
HttpSession httpSession = sessionTracker.getSessionById(sessionId).getId()
println "获取到session后:"+httpSession.getId()
// 使session立即失效
sessionTracker.getSessionById(sessionId).invalidate()
render sessionId
}
}
Hessian
公司不同pool之间提供service都是通过hessian来开放接口的,个人觉得hessian的使用非常简单。做个demo如下:
0.首先创建web工程,并加载hessian.jar。
1.创建service,即我们通过它来提供接口:
public interface BasicService { public void setServiceName(String serverName); public String getServiceName(); public User createuser(); }
2.创建service实现:
public class BasicServiceImpl implements BasicService { private String serviceName; @Override public void setServiceName(String serverName) { this.serviceName = serverName; } @Override public String getServiceName() { return this.serviceName; } @Override public User createuser() { return new User("zhangsan","123456"); } }
3.创建需要通过hessian传递的对象(必须序列化):
public class User implements Serializable { private static final long serialVersionUID = 5792818254468116836L; private String username; private String password; public User(String username,String password) { this.username = username; this.password = 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; } }
4.配置web.xml:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>HessianServer</display-name> <servlet> <servlet-name>basic</servlet-name> <servlet-class>com.caucho.hessian.server.HessianServlet</servlet-class> <init-param> <param-name>service-class</param-name> <param-value>com.loujinhe.service.impl.BasicServiceImpl</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>basic</servlet-name> <url-pattern>/basic</url-pattern> </servlet-mapping> </web-app>
5.创建测试用例:
import java.net.MalformedURLException; import org.junit.Before; import org.junit.Test; import com.caucho.hessian.client.HessianProxyFactory; import com.loujinhe.service.BasicService; public class BasicServiceTest { private BasicService basicService; @Before public void init() throws MalformedURLException { HessianProxyFactory factory = new HessianProxyFactory(); String url = "http://localhost:8080/HessianServer/basic"; basicService = (BasicService)factory.create(BasicService.class,url); } @Test public void testBasic() { basicService.setServiceName("BasicService"); System.out.println(basicService.getServiceName()); System.out.println(basicService.createuser().getUsername()); System.out.println(basicService.createuser().getpassword()); } }
6.启动服务器,运行测试用例,会得到如下结果:
BasicService
zhangsan
123456
今天关于运行中的hessian对象临时变化的讲解已经结束,谢谢您的阅读,如果想了解更多关于Cookie对象与Session对象-java、dubbo服务中的hessian序列化工厂使用hashmap加锁在高并发场景下的问题、Grails通过sessionId获取session对象、Hessian的相关知识,请在本站搜索。
本文标签: