スプリングブート分散システム[1]シロ+ 1 Redisのセッションの共有を実現する練習を拡張し、simplesessionのデシリアライゼーションは、問題と反射向上を見つけることができませんでした...

オリジナルリンク: http://www.cnblogs.com/Halburt/p/10552582.html

序文

試運転前にファビコンの設定をオフにします

spring:
    favicon:
      enabled: false

(nginxの+ブラウザのデバッグの単語を使用している場合)または、2つの要求を見つけることができます
Image.png

シリアル化ツール[fastjsonバージョン1.2.37]

`` `パブリッククラスFastJson2JsonRedisSerializerは{RedisSerializerを実装します

    パブリック静的最終文字セットDEFAULT_CHARSET = Charset.forName( "UTF-8");

    プライベートクラスclazz。

    公共FastJson2JsonRedisSerializer(クラスclazz){
        スーパー();
        this.clazz = clazz。
    }

    @Override
    公共バイト[]シリアライズ(T t)がSerializationExceptionが{スロー
        場合(T == NULL){
            新しいバイトを返す[0]。
        }
        JSON.toJSONString(T、SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET)を返します。
    }

    @Override
    パブリックTのデシリアライズ(バイト[]バイト){SerializationExceptionをスロー
        する場合(バイト== NULLを|| <= 0 bytes.length){
            戻りヌル。
        }
        文字列str =新しい文字列(バイト、DEFAULT_CHARSET)。

        リターン(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源码:

パブリッククラスSimpleSessionはValidatingSession、シリアライズを{実装します

    プライベート過渡SerializableのID。
    プライベート過渡日付startTimestamp。
    プライベート過渡日付stopTimestamp。
    プライベート過渡日lastAccessTime。
    プライベート過渡長いタイムアウト。
    プライベート過渡ブールの有効期限が切れ;
    プライベート過渡文字列のホスト。
    プライベート過渡地図<オブジェクト、オブジェクト>属性。
/ * JDKシリアライゼーションのための指定された出力ストリームにこのオブジェクトを直列化します。

  • オブジェクトのシリアル化のために使用される出力ストリームを@param。
  • このオブジェクトのフィールドのいずれかが、ストリームに書き込むことができない場合はIOExceptionが@throws。
  • @since 1.0
    * /
    プライベートボイドのwriteObject(ObjectOutputStreamのうちは)のIOException {スロー
        out.defaultWriteObjectを呼び出せば、();
        短いalteredFieldsBitMask = getAlteredFieldsBitMask()。
        out.writeShort(alteredFieldsBitMask)。
        IF(!ID = NULL){
            out.writeObject(ID)。
        }
        (startTimestamp = NULL!){もし
            out.writeObject(startTimestamp)。
        }
        (stopTimestamp = NULL!){もし
            out.writeObject(stopTimestamp)。
        }
        (lastAccessTime = NULL!){もし
            out.writeObject(lastAccessTime)。
        }
        場合(タイムアウト= 0リットル!){
            out.writeLong(タイムアウト)。
        }
        (期限切れ){もし
            out.writeBoolean(期限切れ)。
        }
        IF(!ホスト= NULL){
            out.writeUTF(ホスト)。
        }
        {IF(CollectionUtils.isEmpty(属性)!)
            out.writeObject(属性)。
        }
    }

/ *

  • JDK直列化のための指定されたInputStreamに基づいて、このオブジェクトを再構成します。
  • このオブジェクトを移入するためにデータを読み込むために使用する入力ストリームで@param。
  • 入力ストリームが使用できない場合はIOExceptionが@throws。
  • @throws ClassNotFoundExceptionがインスタンス化のために必要な必要なクラスが存在JVMで利用できない場合
  • @since 1.0
    * /
    @SuppressWarnings({ "をチェック"})
    プライベートボイドのreadObject(中のObjectInputStreamは)にIOException、ClassNotFoundExceptionが{スロー

***发现transient修饰,所以Fastjson不会对这些transient属性进行持久化,所以有了方案二,重写可以json序列化的对象
同时发现有writeObject()方法写着“ Serializes this object to the specified output stream for JDK Serialization.”,
所以有了方案一,修改序列化工具( 默认使用JdkSerializationRedisSerializer,这个序列化模式会将value序列化成字节码)
问题我们就好对症下药了***
## 方案一:

修改序列化工具类 (`这个方式其实有问题`)

パブリッククラスFastJson2JsonRedisSerializerはRedisSerializer {実装
    プライベートクラスclazzを。
    公共FastJson2JsonRedisSerializer(クラスclazz){
        スーパー();
        this.clazz = clazz。
    }
    @Override
    公共バイト[]シリアライズ(T tの){
        ObjectUtils.serialize(t)を返します。
    }
    @Override
    パブリックTのデシリアライズ(バイト[]バイト){
        リターン(T)ObjectUtils.unserialize(バイト)。
    }
}

### ObjectUtils的方法如下:

/ **

  • 直列化されたオブジェクト
  • @paramオブジェクト
  • @return
    * /
    パブリック静的バイト[]シリアライズ(Objectオブジェクト){
       にObjectOutputStream OOS = NULL;
       ByteArrayOutputStreamたBAO = NULL;
       してみてください{
          (対象= nullを!){場合
             のBAO =新しいByteArrayOutputStream();
             OOS =新しいObjectOutputStreamの(のBAO)。
             oos.writeObject(オブジェクト)。
             baos.toByteArrayを返します();
          }
       }キャッチ(例外e){
          e.printStackTrace();
       }
       はnullを返します。
    }

/ **

  • 非直列化されたオブジェクト
  • @paramバイト
  • @return
    * /
    パブリック静的オブジェクトアンシリアライズ(バイト[]バイト){
       れるByteArrayInputStream BAIS = NULL;
       {しようと
          するif(!バイト= NULL && bytes.length> 0){
             BAIS =新しいするByteArrayInputStream(バイト)。
             ObjectInputStreamのOIS =新しいObjectInputStreamの(BAIS)。
             ois.readObject返します();
          }
       }キャッチ(例外e){
          e.printStackTrace();
       }
       は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
保護されたセッションnewSessionInstance(のSessionContextコンテキスト){
SimpleSessionセッション=新しいMyRedisSession(context.getHost())。
// session.setId(IdGen.uuid());
session.setTimeout(SessionUtils.SESSION_TIME)。
セッションを返します。
}

#### 由方案二引发的另一个问题就是:
**`在微服务开发过程中,为了使用方便经常会将频繁访问的信息如用户、权限等放置到SESSION中,便于服务访问,而且,微服务间为了共享SESSION,通常会使用Redis共享存储。但是这样就会有一个问题,在封装Request对象时会将当前SESSION中所有属性对象反序列化,反序列化都成功以后,将SESSION对象生成。如果有一个微服务将本地的自定义Bean对象放置到SESSION中,则其他微服务都将出现反序列化失败,请求异常,服务将不能够使用了,这是一个灾难性问题。`**
##### 以下是为了解决下面问题提出来的一种思路。
反序列化失败在于Attribute中添加了复杂对象,由此推出以下解决方案:

1. 将复杂对象的(即非基本类型的)Key进行toString转换(转换之后再MD5缩减字符串,或者用类名代替)
2. 将复杂对象的(即非基本类型的)Value进行JSON化(不使用不转换的懒加载模式)

`注意:
日期对象的处理(单独处理)`

  / **
     *通过类型转换、将ストリング反序列化成对象
     * @paramキー
     * @param値
     * @return
     * /
    パブリックオブジェクトgetObjectValue(文字列キー、文字列値){
        IF(キー==ヌル||値== NULL ){
           NULLを返します。
        }
        文字列CLZ = key.replace(FLAG_STR、 "");
        試す{
           クラスAClassは= Class.forNameの(CLZ)。
           IF(aClass.equals(Date.class)){
               DateUtils.parseDate(値)を返します。
           }
          JSONObject.parseObject(値、AClassは)を返します。
        }キャッチ(ClassNotFoundExceptionが電子){
            e.printStackTrace();
        }
//故障逆シリアル化プロセスは、JSON進む
        戻りJSONObject.parseObject(値);
    }

`` `
このような治療は、すべてのシステム・キャッシュ間で共有することができた後、
唯一の欠点は、あまりにも複雑で、他のシステムの変更につながる可能性があり、デシリアライゼーションの故障につながる(またはこれを再び次の実験を議論するような複雑な努力があるので、我々は考えることができます)JWTによって

还有一种方案是将复杂对象放到redis中去,实行懒加载机制(不用的复杂对象,不从redis里获取,暂未实现测试)

ます。https://www.cnblogs.com/Halburt/p/10552582.htmlで再現

おすすめ

転載: blog.csdn.net/weixin_30521161/article/details/94785384
おすすめ