编程网站哪个好,简述什么是虚拟主机,关联词有哪些,网站切换中英文前言 调试之前请先关闭Favicon配置 spring:favicon:enabled: false 不然会发现有2个请求#xff08;如果用nginx 浏览器调试的话#xff09; 序列化工具类【fastjson版本1.2.37】 public class FastJson2JsonRedisSerializer implements RedisSerializer { public static fin…前言 调试之前请先关闭Favicon配置 spring:favicon:enabled: false 不然会发现有2个请求如果用nginx 浏览器调试的话 序列化工具类【fastjson版本1.2.37】 public class FastJson2JsonRedisSerializer implements RedisSerializer { public static final Charset DEFAULT_CHARSET Charset.forName(UTF-8); private Class clazz; public FastJson2JsonRedisSerializer(Class clazz) { super(); this.clazz clazz; } Override public byte[] serialize(T t) throws SerializationException { if (t null) { return new byte[0]; } return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET); } Override public T deserialize(byte[] bytes) throws SerializationException { if (bytes null || bytes.length 0) { return null; } String str new String(bytes, DEFAULT_CHARSET); return (T) JSON.parseObject(str, clazz); } } org.apache.shiro.session.mgt.SimpleSession存储到redis中会发现已经丢失了所有属性![Image [1].png](https://upload-images.jianshu.io/upload_images/231328-ab9c9ca3c2b43710.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)#### 查看SimpleSession源码public class SimpleSession implements ValidatingSession, Serializable { private transient Serializable id; private transient Date startTimestamp; private transient Date stopTimestamp; private transient Date lastAccessTime; private transient long timeout; private transient boolean expired; private transient String host; private transient MapObject, Object attributes; /* Serializes this object to the specified output stream for JDK Serialization. param out output stream used for Object serialization.throws IOException if any of this objects fields cannot be written to the stream.since 1.0 */ private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); short alteredFieldsBitMask getAlteredFieldsBitMask(); out.writeShort(alteredFieldsBitMask); if (id ! null) { out.writeObject(id); } if (startTimestamp ! null) { out.writeObject(startTimestamp); } if (stopTimestamp ! null) { out.writeObject(stopTimestamp); } if (lastAccessTime ! null) { out.writeObject(lastAccessTime); } if (timeout ! 0l) { out.writeLong(timeout); } if (expired) { out.writeBoolean(expired); } if (host ! null) { out.writeUTF(host); } if (!CollectionUtils.isEmpty(attributes)) { out.writeObject(attributes); } }/* Reconstitutes this object based on the specified InputStream for JDK Serialization. param in the input stream to use for reading data to populate this object.throws IOException if the input stream cannot be used.throws ClassNotFoundException if a required class needed for instantiation is not available in the present JVMsince 1.0 */ SuppressWarnings({unchecked}) private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
***发现transient修饰所以Fastjson不会对这些transient属性进行持久化所以有了方案二重写可以json序列化的对象
同时发现有writeObject方法写着“ Serializes this object to the specified output stream for JDK Serialization.”
所以有了方案一修改序列化工具 默认使用JdkSerializationRedisSerializer这个序列化模式会将value序列化成字节码
问题我们就好对症下药了***
## 方案一修改序列化工具类 这个方式其实有问题public class FastJson2JsonRedisSerializer implements RedisSerializer { private Class clazz; public FastJson2JsonRedisSerializer(Class clazz) { super(); this.clazz clazz; } Override public byte[] serialize(T t) { return ObjectUtils.serialize(t); } Override public T deserialize(byte[] bytes) { return (T) ObjectUtils.unserialize(bytes); } } ### ObjectUtils的方法如下/** 序列化对象param objectreturn */ public static byte[] serialize(Object object) { ObjectOutputStream oos null; ByteArrayOutputStream baos null; try { if (object ! null){ baos new ByteArrayOutputStream(); oos new ObjectOutputStream(baos); oos.writeObject(object); return baos.toByteArray(); } } catch (Exception e) { e.printStackTrace(); } return null; }/** 反序列化对象param bytesreturn */ public static Object unserialize(byte[] bytes) { ByteArrayInputStream bais null; try { if (bytes ! null bytes.length 0){ bais new ByteArrayInputStream(bytes); ObjectInputStream ois new ObjectInputStream(bais); return ois.readObject(); } } catch (Exception e) { e.printStackTrace(); } return null; }
***此方案会严重依赖对象class如果反序列化时class对象不存在则会报错
修改为 JdkSerializationRedisSerializer
***![Image [2].png](https://upload-images.jianshu.io/upload_images/231328-900964ebbd4757e2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/900)### 方案二***继承SimpleSession并重写
让相关的字段可以被序列化(不被transient修饰)
重写之后一定要重写SessionManager里的方法*** Override protected Session newSessionInstance(SessionContext context) { SimpleSession session new MyRedisSession(context.getHost()); // session.setId(IdGen.uuid()); session.setTimeout(SessionUtils.SESSION_TIME); return session; } #### 由方案二引发的另一个问题就是
**在微服务开发过程中为了使用方便经常会将频繁访问的信息如用户、权限等放置到SESSION中便于服务访问而且微服务间为了共享SESSION通常会使用Redis共享存储。但是这样就会有一个问题在封装Request对象时会将当前SESSION中所有属性对象反序列化反序列化都成功以后将SESSION对象生成。如果有一个微服务将本地的自定义Bean对象放置到SESSION中则其他微服务都将出现反序列化失败请求异常服务将不能够使用了这是一个灾难性问题。**
##### 以下是为了解决下面问题提出来的一种思路。
反序列化失败在于Attribute中添加了复杂对象由此推出以下解决方案1. 将复杂对象的即非基本类型的Key进行toString转换转换之后再MD5缩减字符串或者用类名代替
2. 将复杂对象的即非基本类型的Value进行JSON化不使用不转换的懒加载模式注意
日期对象的处理单独处理 /** * 通过类型转换将String反序列化成对象 * param key * param value * return */ public Object getObjectValue(String key,String value){ if(key null || value null){ return null; } String clz key.replace(FLAG_STR,); try { Class aClass Class.forName(clz); if(aClass.equals(Date.class)){ return DateUtils.parseDate(value); } return JSONObject.parseObject(value,aClass); } catch (ClassNotFoundException e) { e.printStackTrace(); } // 如果反序列化失败就进行json化处理 return JSONObject.parseObject(value); } 经过如此处理可以在所有系统里共享缓存唯一缺点就是太复杂了可能引起其他系统的修改导致反序列化失败这个下次再讨论或者实验因为有这么复杂的功夫就可以考虑用JWT 还有一种方案是将复杂对象放到redis中去实行懒加载机制不用的复杂对象不从redis里获取暂未实现测试 转载于:https://www.cnblogs.com/Halburt/p/10552582.html