最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

springsession全能序列化實踐方案

 更新時間:2026年04月17日 08:40:52   作者:Tirzano  
文章主要介紹了SpringSession的“全能序列化”方案,即使用JSON格式替代Java原生序列化來存儲會話數(shù)據(jù),JSON序列化方案能提高系統(tǒng)性能、增強跨語言服務(wù)調(diào)用能力、提升類版本兼容性,并具有更高的安全性,感興趣的朋友跟隨小編一起看看吧

構(gòu)建一個可靠、高效的分布式會話管理方案,序列化是最核心的環(huán)節(jié)。Spring Session的“全能序列化”方案,并非指一個萬能工具,而是一套以 GenericJackson2JsonRedisSerializer 為核心的自定義JSON序列化策略。

簡單來說,就是放棄Spring Session默認的Java原生序列化(JdkSerializationRedisSerializer),轉(zhuǎn)而使用JSON格式來存儲會話數(shù)據(jù)。

為什么需要“全能序列化”?

Spring Session默認的Java原生序列化存在一些明顯短板,而JSON序列化則能很好地彌補這些問題-17。

對比維度Java 原生序列化 (JdkSerializationRedisSerializer)JSON 序列化 (GenericJackson2JsonRedisSerializer)
可讀性? 二進制格式,存儲在Redis中為亂碼,不便調(diào)試? 純文本格式,可在Redis客戶端直接查看,方便調(diào)試和運維
性能?? 性能較差,序列化后字節(jié)數(shù)組較大,影響網(wǎng)絡(luò)和內(nèi)存開銷? 性能更好,序列化后數(shù)據(jù)體積更小,效率更高
跨語言? 僅限Java,其他語言(如Python, Node.js)無法解析? 基于JSON,支持跨語言服務(wù)調(diào)用和數(shù)據(jù)處理
類版本兼容性? 對serialVersionUID極其敏感,類結(jié)構(gòu)變更可能導(dǎo)致舊會話無法反序列化? 通過在JSON中保留類型信息,對類的小幅變更(如增加字段)有較好兼容性
安全性?? 存在反序列化漏洞風險? 相對更安全

因此,采用JSON序列化方案能有效解決由序列化引發(fā)的諸多生產(chǎn)問題,讓你的系統(tǒng)更健壯。

下面通過代碼示例給大家演示:

package com.kongjs.common.session.config;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.kongjs.common.session.jackson.RestJacksonModule;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.serializer.JacksonJsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.security.jackson.SecurityJacksonModule;
import org.springframework.security.jackson.SecurityJacksonModules;
import tools.jackson.databind.DefaultTyping;
import tools.jackson.databind.JacksonModule;
import tools.jackson.databind.cfg.MapperBuilder;
import tools.jackson.databind.json.JsonMapper;
import tools.jackson.databind.jsontype.BasicPolymorphicTypeValidator;
import tools.jackson.databind.module.SimpleModule;
import java.util.ArrayList;
import java.util.List;
@Configuration(proxyBeanMethods = false)
public class SessionConfig implements BeanClassLoaderAware {
    private ClassLoader beanClassloader;
    @Bean
    public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
        return new JacksonJsonRedisSerializer<>(objectMapper(), Object.class);
    }
    private JsonMapper objectMapper() {
        List<JacksonModule> modules = SecurityJacksonModules.getModules(this.beanClassloader);
        RestJacksonModule restJacksonModule = new RestJacksonModule();
        List<JacksonModule> restModules = new ArrayList<>(modules);
        restModules.add(restJacksonModule);
        applyPolymorphicTypeValidator(restModules, null);
        return JsonMapper.builder().addModules(restModules).build();
    }
    // 放開某些類型
    private static void applyPolymorphicTypeValidator(List<JacksonModule> modules, BasicPolymorphicTypeValidator.Builder typeValidatorBuilder) {
        BasicPolymorphicTypeValidator.Builder builder = (typeValidatorBuilder != null) ? typeValidatorBuilder
                : BasicPolymorphicTypeValidator.builder();
        for (JacksonModule module : modules) {
            if (module instanceof SecurityJacksonModule securityModule) {
                securityModule.configurePolymorphicTypeValidator(builder);
            }
        }
        modules.add(new SimpleModule() {
            @Override
            public void setupModule(SetupContext context) {
                ((MapperBuilder<?, ?>) context.getOwner()).activateDefaultTyping(builder.build(),
                        DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
            }
        });
    }
    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.beanClassloader = classLoader;
    }
}
package com.kongjs.common.session.jackson;
import com.kongjs.common.session.authentication.RestAuthentication;
import com.kongjs.common.session.dto.AccountInfo;
import org.springframework.security.jackson.SecurityJacksonModule;
import tools.jackson.core.Version;
import tools.jackson.databind.jsontype.BasicPolymorphicTypeValidator;
import java.util.LinkedHashMap;
// 使用這個方便
public class RestJacksonModule extends SecurityJacksonModule {
    public RestJacksonModule() {
        super(RestJacksonModule.class.getName(), new Version(1, 0, 0, null, null, null));
    }
    public RestJacksonModule(String name, Version version) {
        super(name, version);
    }
    @Override
    public void configurePolymorphicTypeValidator(BasicPolymorphicTypeValidator.Builder builder) {
        builder.allowIfBaseType(Object.class); // 允許 Object 所有子類型(包含 Long/Integer 等)
        builder.allowIfBaseType(Long.class);   // 顯式允許 Long 類型
        builder.allowIfBaseType(LinkedHashMap.class); // 兼容認證信息中的 Map 類型
        builder.allowIfSubType(RestAuthentication.class);
        builder.allowIfSubType(AccountInfo.class);
    }
    @Override
    public void setupModule(SetupContext context) {
        super.setupModule(context);
        context.setMixIn(RestAuthentication.class, RestAuthenticationMixin.class);
        context.setMixIn(AccountInfo.class, AccountInfoMixin.class);
    }
}
package com.kongjs.common.session.authentication;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.jspecify.annotations.Nullable;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.util.Assert;
import java.io.Serial;
import java.util.Collection;
@JsonInclude(JsonInclude.Include.NON_NULL)
public class RestAuthentication extends AbstractAuthenticationToken {
    @Serial
    private static final long serialVersionUID = 20260313L;
    private final Object principal;
    private Object credentials;
    public RestAuthentication(Object principal, Object credentials) {
        super((Collection<? extends GrantedAuthority>) null);
        this.principal = principal;
        this.credentials = credentials;
        super.setAuthenticated(false);
    }
    public RestAuthentication(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
        super(authorities);
        this.principal = principal;
        this.credentials = credentials;
        super.setAuthenticated(true);
    }
    public static RestAuthentication unauthenticated(Object principal, Object credentials) {
        return new RestAuthentication(principal, credentials);
    }
    public static RestAuthentication authenticated(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
        return new RestAuthentication(principal, credentials, authorities);
    }
    protected RestAuthentication(Builder<?> builder) {
        super(builder);
        this.principal = builder.principal;
        this.credentials = builder.credentials;
    }
    @Override
    public @Nullable Object getPrincipal() {
        return principal;
    }
    @Override
    public @Nullable Object getCredentials() {
        return credentials;
    }
    @Override
    public void eraseCredentials() {
        super.eraseCredentials();
        this.credentials = null;
    }
    public Builder<?> toBuilder() {
        return new Builder<>(this);
    }
    public static class Builder<B extends Builder<B>> extends AbstractAuthenticationBuilder<B> {
        private @Nullable Object principal;
        private @Nullable Object credentials;
        protected Builder(RestAuthentication token) {
            super(token);
            this.principal = token.principal;
            this.credentials = token.credentials;
        }
        public B principal(@Nullable Object principal) {
            Assert.notNull(principal, "principal cannot be null");
            this.principal = principal;
            return (B) this;
        }
        public B credentials(@Nullable Object credentials) {
            this.credentials = credentials;
            return (B) this;
        }
        public RestAuthentication build() {
            return new RestAuthentication(this);
        }
    }
}
package com.kongjs.common.session.jackson;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import tools.jackson.databind.annotation.JsonDeserialize;
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE)
@JsonDeserialize(using = RestAuthenticationDeserializer.class)
public class RestAuthenticationMixin {
}
package com.kongjs.common.session.jackson;
import com.kongjs.common.session.authentication.RestAuthentication;
import org.jspecify.annotations.Nullable;
import org.springframework.security.core.GrantedAuthority;
import tools.jackson.core.JacksonException;
import tools.jackson.core.JsonParser;
import tools.jackson.core.exc.StreamReadException;
import tools.jackson.core.type.TypeReference;
import tools.jackson.databind.DatabindException;
import tools.jackson.databind.DeserializationContext;
import tools.jackson.databind.JsonNode;
import tools.jackson.databind.ValueDeserializer;
import tools.jackson.databind.node.MissingNode;
import java.util.List;
public class RestAuthenticationDeserializer extends ValueDeserializer<RestAuthentication> {
    private static final TypeReference<List<GrantedAuthority>> GRANTED_AUTHORITY_LIST = new TypeReference<>() {
    };
    /**
     * This method construct {@link RestAuthentication} object from
     * serialized json.
     *
     * @param jp   the JsonParser
     * @param ctxt the DeserializationContext
     * @return the user
     * @throws JacksonException if an error during JSON processing occurs
     */
    @Override
    public RestAuthentication deserialize(JsonParser jp, DeserializationContext ctxt) throws JacksonException {
        JsonNode jsonNode = ctxt.readTree(jp);
        boolean authenticated = readJsonNode(jsonNode, "authenticated").asBoolean();
        JsonNode principalNode = readJsonNode(jsonNode, "principal");
        Object principal = getPrincipal(ctxt, principalNode);
        JsonNode credentialsNode = readJsonNode(jsonNode, "credentials");
        Object credentials = getCredentials(credentialsNode);
        JsonNode authoritiesNode = readJsonNode(jsonNode, "authorities");
        List<GrantedAuthority> authorities = ctxt.readTreeAsValue(authoritiesNode,
                ctxt.getTypeFactory().constructType(GRANTED_AUTHORITY_LIST));
        RestAuthentication token = (!authenticated)
                ? RestAuthentication.unauthenticated(principal, credentials)
                : RestAuthentication.authenticated(principal, credentials, authorities);
        JsonNode detailsNode = readJsonNode(jsonNode, "details");
        if (detailsNode.isNull() || detailsNode.isMissingNode()) {
            token.setDetails(null);
        } else {
            Object details = ctxt.readTreeAsValue(detailsNode, Object.class);
            token.setDetails(details);
        }
        return token;
    }
    private Object getPrincipal(DeserializationContext ctxt, JsonNode principalNode) throws StreamReadException, DatabindException {
        if (principalNode.isObject()) {
            return ctxt.readTreeAsValue(principalNode, Object.class);
        }
        return principalNode.asString();
    }
    private @Nullable Object getCredentials(JsonNode credentialsNode) {
        if (credentialsNode.isNull() || credentialsNode.isMissingNode()) {
            return null;
        }
        return credentialsNode.asString();
    }
    private JsonNode readJsonNode(JsonNode jsonNode, String field) {
        return jsonNode.has(field) ? jsonNode.get(field) : MissingNode.getInstance();
    }
}

到此這篇關(guān)于springsession全能序列化實踐方案的文章就介紹到這了,更多相關(guān)springsession序列化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • springboot jdbctemplate如何實現(xiàn)多數(shù)據(jù)源

    springboot jdbctemplate如何實現(xiàn)多數(shù)據(jù)源

    這篇文章主要介紹了springboot jdbctemplate如何實現(xiàn)多數(shù)據(jù)源問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • java獲取機器碼簡單實現(xiàn)demo

    java獲取機器碼簡單實現(xiàn)demo

    這篇文章主要為大家介紹了java獲取機器碼的簡單實現(xiàn)demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-11-11
  • CentOS 7快速安裝jdk

    CentOS 7快速安裝jdk

    這篇文章主要為大家詳細介紹了CentOS 7快速安裝jdk的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • Spring Security注解方式權(quán)限控制過程

    Spring Security注解方式權(quán)限控制過程

    這篇文章主要介紹了Spring Security注解方式權(quán)限控制過程,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-03-03
  • Java中break、continue、return語句的使用區(qū)別對比

    Java中break、continue、return語句的使用區(qū)別對比

    這篇文章主要介紹了Java中break、continue、return語句的使用區(qū)別對比,本文用非常清爽簡明的語言總結(jié)了這三個關(guān)鍵字的使用技巧,并用一個實例對比使用結(jié)果,需要的朋友可以參考下
    2015-06-06
  • Spring?Boot中記錄用戶系統(tǒng)操作流程

    Spring?Boot中記錄用戶系統(tǒng)操作流程

    這篇文章主要介紹了如何在Spring?Boot中記錄用戶系統(tǒng)操作流程,將介紹如何在Spring?Boot中使用AOP(面向切面編程)和日志框架來實現(xiàn)用戶系統(tǒng)操作流程的記錄,需要的朋友可以參考下
    2023-07-07
  • lambda表達式解決java后臺分組排序過程解析

    lambda表達式解決java后臺分組排序過程解析

    這篇文章主要介紹了lambda表達式解決java后臺分組排序過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-10-10
  • springcloud gateway 映射失效的解決方案

    springcloud gateway 映射失效的解決方案

    這篇文章主要介紹了springcloud gateway 映射失效的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • 教你用JDK編譯Java文件的方法

    教你用JDK編譯Java文件的方法

    這篇文章主要介紹了教你用JDK編譯Java文件的方法,分步驟給大家介紹了設(shè)置環(huán)境變量的方法,本文通過圖文并茂的形式給大家介紹的非常詳細,需要的朋友可以參考下
    2022-01-01
  • java如何自定義注解

    java如何自定義注解

    這篇文章主要介紹了java如何自定義注解問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-02-02

最新評論

美姑县| 锦州市| 黔西县| 莱州市| 子长县| 邹平县| 蓝田县| 金山区| 贺州市| 渝北区| 安顺市| 扶风县| 禄丰县| 通许县| 安仁县| 白银市| 顺昌县| 密山市| 库尔勒市| 揭东县| 徐闻县| 崇阳县| 烟台市| 醴陵市| 朝阳县| 图们市| 宜兰市| 普洱| 安康市| 浏阳市| 卢湾区| 永胜县| 监利县| 温宿县| 鄂伦春自治旗| 韩城市| 林甸县| 钟山县| 尖扎县| 云和县| 阆中市|