spring mvc环境配置spring-data-redis进行应用多实例间session共享

2 篇文章 0 订阅
2 篇文章 0 订阅

一、redis 环境准备

  1. 打开redis配置文件redis.conf
  2. 修改redis.conf文件
    notify-keyspace-events Egx
    
  3. 重启redis服务

二、POM文件依赖引入

        <!-- session共享, 采用spring-session-data-redis依赖 -->
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
            <version>1.3.1.RELEASE</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.data</groupId>
                    <artifactId>spring-data-redis</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>1.7.1.RELEASE</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-context-support</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

二、web.xml 配置

在所有filter的最前面,增加如下filter(不要改这个filter名称)

<filter>
    <filter-name>springSessionRepositoryFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>springSessionRepositoryFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

三、spring application context xml配置

增加如下配置

    <!-- 让Spring Session不再执行config命令 -->
	<util:constant static-field="org.springframework.session.data.redis.config.ConfigureRedisAction.NO_OP"/>

	<bean id="redisSessionSerializer"
		  class="com.some.company.CustomGenericFastJsonRedisSerializer" />

	<bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer" />

	<bean id="sessionRedisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
		  p:keySerializer-ref="stringRedisSerializer"
		  p:hashKeySerializer-ref="stringRedisSerializer"
		  p:valueSerializer-ref="redisSessionSerializer"
		  p:hashValueSerializer-ref="redisSessionSerializer"
		  p:connectionFactory-ref="redisConnectionFactory" />

	<context:annotation-config />
	<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"
		  p:defaultRedisSerializer-ref="redisSessionSerializer" p:configureRedisAction="NO_OP" />

四、session 序列化器定制化

上面第三步有个定制化的序列化器, 用于处理session(本质是个map)中存储的,不容易做序列化的属性对象。

例如没有实现Serilizable接口的类, 或者说,使用通用的序列化方法,不太容易做序列化(反序列化)的对象。

需要自己定制序列化策略:

  1. 调用定制化策略, 得到包含某个session对象S的字符串A。
  2. 将字符串A按照标准的字符串序列化方式序列化到redis中。
  3. 反序列化时, 用标准的字符串反序列化方式从redis中反序列化出来字符串A。
  4. 从A中提取信息,用定制的反序列化策略,构造对应的session对象类S。

序列化元数据类

@Data
public class CustomGenericFastJsonRedisBean {
    // bean 序列化原始类全路径类名
    private String className;
    // 原始类定制序列化策略生成的字符串
    private String classContent;
    // 如果是列表对象,列表中元素的全路径类名
    private String arrayItemClass;
}

定制序列化

package com.some.company.util;

...

public class CustomGenericFastJsonRedisSerializer extends GenericJackson2JsonRedisSerializer {
    private static final Logger log = LoggerFactory.getLogger(CustomGenericFastJsonRedisSerializer.class);

    @Autowired
    private UserService userService;

    @Override
    public byte[] serialize(Object source) throws SerializationException {
        try {
            if (source == null) {
                log.info("source null");
                return new byte[0];
            } else {
                String classname = source.getClass().getName();
                CustomGenericFastJsonRedisBean customGenericFastJsonRedisBean = new CustomGenericFastJsonRedisBean();
                Gson gson = new Gson();
                String objectStrOrigin;
                if (StringUtils.equals("com.some.company.User", classname)) {
                    objectStrOrigin = Jackson2Helper.toJsonString(source);
                } else if (StringUtils.equals("org.springframework.security.core.context.SecurityContextImpl",
                        classname)) {
                    SecurityContextImpl securityContext = (SecurityContextImpl) source;
                    CasAuthenticationToken oneToGo = (CasAuthenticationToken) securityContext.getAuthentication();

                    objectStrOrigin = buildCasAuthenticationTokenStr(oneToGo);
                    log.info("redis class : >{}< bean content : >{}<", classname, objectStrOrigin);
                } else if (StringUtils.equals("java.util.ArrayList", classname)) {
                    ArrayList<?> oneList = (ArrayList<?>) source;
                    if (CollectionUtils.isNotEmpty(oneList)) {
                        String itemClassname = oneList.get(0).getClass().getName();
                        customGenericFastJsonRedisBean.setArrayItemClass(itemClassname);
                        objectStrOrigin = JSON.toJSONString(source);
                        log.info("redis class : >{}<", itemClassname);
                    } else {
                        objectStrOrigin = JSON.toJSONString(source);
                        log.info("redis class : Object");
                    }
                } else {
                    objectStrOrigin = gson.toJson(source);
                    log.info("redis class : >{}< bean content : >{}<", classname, objectStrOrigin);
                }
//                String objectStrOrigin = Jackson2Helper.toJsonString(source);
                customGenericFastJsonRedisBean.setClassName(classname);
                customGenericFastJsonRedisBean.setClassContent(objectStrOrigin);
                String objectStr = gson.toJson(customGenericFastJsonRedisBean);
                return super.serialize(objectStr);
            }
        } catch (Exception e) {
            log.warn("serialize session Object error!", e);
        }
        return new byte[0];
    }

    @HibernateSessionAround
    @Override
    public Object deserialize(@Nullable byte[] bytes) {
        Object deserialObj = null;
        try {
            if (bytes == null || bytes.length <= 0) {
                log.warn("bytes empty");
            } else {
                String outStr = super.deserialize(bytes, String.class);
                if (StringUtils.isBlank(outStr)) {
                    log.warn("empty outStr");
                } else {
                    Gson gson = new Gson();
                    CustomGenericFastJsonRedisBean customGenericFastJsonRedisBean =
                            gson.fromJson(outStr, CustomGenericFastJsonRedisBean.class);

                    if (customGenericFastJsonRedisBean == null) {
                        log.warn("customGenericFastJsonRedisBean is null");
                    } else {
                        String redisOutClassName = customGenericFastJsonRedisBean.getClassName();
                        String redisOutContent = customGenericFastJsonRedisBean.getClassContent();
                        String arrayItemClass = customGenericFastJsonRedisBean.getArrayItemClass();
                        if (StringUtils.isBlank(redisOutClassName)) {
                            log.warn("customGenericFastJsonRedisBean class name null");
                        } else {
                            Class redisOutClass = Class.forName(redisOutClassName);
                            if (StringUtils.equals("com.some.company.User", redisOutClassName)) {
                                com.some.company.User userOrigin =
                                        Jackson2Helper.parsonObject(redisOutContent,
                                                new TypeReference<com.some.company.User.User>() { } );

                                if (userOrigin != null) {
                                    Long userId = userOrigin.getId();
                                    com.some.company.User user = userService.findByUserId(userId);
                                    log.info("user dept name {}", user.getDeptName());
                                    deserialObj = user;
                                } else {
                                    deserialObj = null;
                                }

                                log.info("redisOutClassName: >{}<, redisOutContent: >{}<",
                                        redisOutClassName, redisOutContent);

                            } else if (StringUtils.equals(
                                    "org.springframework.security.core.context.SecurityContextImpl",
                                    redisOutClassName)) {
                                JSONObject jsonObject = JSON.parseObject(redisOutContent);
                                CasAuthenticationToken casAuthenticationToken =
                                        buildCasAuthenticationToken(jsonObject);
                                SecurityContextImpl securityContext = new SecurityContextImpl();
                                securityContext.setAuthentication(casAuthenticationToken);
                                deserialObj = securityContext;
                            } else if (StringUtils.equals("java.util.ArrayList", redisOutClassName)) {
                                if (StringUtils.isNotBlank(arrayItemClass)) {
                                    Class redisOutClassArray = Class.forName(arrayItemClass);
                                    deserialObj = JSON.parseArray(redisOutContent, redisOutClassArray);
                                    log.info("arrayItemClass : >{}<", arrayItemClass);
                                } else {
                                    deserialObj = JSON.parseArray(redisOutContent, Object.class);
                                    log.info("arrayItemClass : >Object<");
                                }
                            } else {
                                deserialObj = gson.fromJson(redisOutContent, redisOutClass);
                                log.info("redisOutClassName: >{}<, redisOutContent: >{}<",
                                        redisOutClassName, redisOutContent);
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.warn("deserialize session Object error!", e);
        }
        return deserialObj;
    }

    private String buildCasAuthenticationTokenStr(CasAuthenticationToken oneToGo) {
        JSONObject jsonObject = new JSONObject();
        ...
        return JSON.toJSONString(jsonObject);
    }

    private CasAuthenticationToken buildCasAuthenticationToken(JSONObject jsonObject) {
        ...
        CasAuthenticationToken casAuthenticationToken =
                new CasAuthenticationToken("an_id_for_this_auth_provider_only",
                        principal,
                        credentials,
                        grantedAuthorityList,
                        userDetails,
                        assertionImpl);
        return casAuthenticationToken;
    }

}

五、总结

理论上,用spring data redis 做 session共享,可以根据自己工程的鉴权场景,做任意的序列化定制,来支持服务多实例间session共享。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值