首先:
我们在部署项目的时候有时候需要集群部署来保证单个平台掉线之后还可以继续给用户提供服务等,保证我们的线上业务,所以需要nginx集群去部署。这样就可以保证有一个服务器宕机之后,线上的业务也不会给我们造成损失。
我们演示的话需要三台机器是最好的,两台机器也是可以的。多起两个虚拟机而已,在每台服务器部署一个项目,然后配置到nginxl集群里面,配置好每个服务器的权重信息或者是他的匹配规则。配置好之后我们需要配置session共享,因为不同服务之间的会话是不能共享的,我们可以把会话序列化之后存储到redis中。
首先取用的系统是: windows 10,nginx尽量选择版本高一点的,低版本不支持的东西太多了。
项目采用的框架是:SpringBoot,Shiro。
了解到Shiro管理Session(会话)是在SessionManger里面,在sessionManger里面注入sessionDao,所以我们需要重写sessionDao.
话不多说,上代码:
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import java.io.Serializable;
import java.util.Collection;
/**
* created with IntelliJ IDEA
*
* @author: create by limu
* Date: 2020/12/14
* Time:21:47
*/
public class RedisSessionDao extends AbstractSessionDAO {
@Override
protected Serializable doCreate(Session session) {
return null;
}
@Override
protected Session doReadSession(Serializable sessionId) {
return null;
}
@Override
public void update(Session session) throws UnknownSessionException {
}
@Override
public void delete(Session session) {
}
@Override
public Collection<Session> getActiveSessions() {
return null;
}
}
我们可以看到,里面重写了五个方法:doCreate(创建会话),doReadSession(读取会话),update(修改会话),delete(删除会话),getActiveSession(获取会话集合)。
其实在这里就和数据库的增删改查是一样的,每次客户端和服务端有会话操作的时候都会调用这个方法。之所以选择redis是因为redis的读写比较快一点。
全部代码如下:
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.zjxf.base.customer.SysConst;
import com.zjxf.cache.CacheKeys;
import com.zjxf.common.ShiroConst;
import com.zjxf.redis.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.SimpleSession;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.*;
import java.util.Collection;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* created with IntelliJ IDEA
*
* @author: create by limu
* Date: 2020/7/20
* Time:11:58
*/
@Slf4j
@Service
public class RedisSessionDao extends AbstractSessionDAO {
@Autowired
private RedisService redisService;
public RedisSessionDao() {
super();
}
public RedisSessionDao(RedisService redisService) {
super();
this.redisService = redisService;
}
@Override
protected Serializable doCreate(Session session) {
log.debug("建立会话");
Serializable sessionId = this.generateSessionId(session);
this.assignSessionId(session, sessionId);
JSONObject redisJson = new JSONObject();
redisJson.put("session", sessionToByte(session));
redisService.setContainExpire(CacheKeys.getSystemColonyRedisSession(String.valueOf(session.getId())), redisJson, ShiroConst.SHIRO_SESSION_SESSION_MAX_AGE, TimeUnit.SECONDS);
return sessionId;
}
@Override
protected Session doReadSession(Serializable sessionId) {
if (Objects.nonNull(sessionId)) {
Optional<JSONObject> redisJsonOptional = redisService.get(CacheKeys.getSystemColonyRedisSession(String.valueOf(sessionId)));
return redisJsonOptional.map(item -> byteToSession(item.getBytes("session"))).orElse(null);
} else {
return null;
}
}
@Override
public void update(Session session) throws UnknownSessionException {
if (Objects.nonNull(session) && Objects.nonNull(session.getId())) {
JSONObject redisJson = new JSONObject();
redisJson.put("session", sessionToByte(session));
redisService.setContainExpire(CacheKeys.getSystemColonyRedisSession(String.valueOf(session.getId())), redisJson, ShiroConst.SHIRO_SESSION_SESSION_MAX_AGE, TimeUnit.SECONDS);
}
}
@Override
public void delete(Session session) {
log.debug("删除会话");
if (Objects.nonNull(session) && Objects.nonNull(session.getId())) {
redisService.delete(CacheKeys.getSystemColonyRedisSession(String.valueOf(session.getId())));
}
}
@Override
public Collection<Session> getActiveSessions() {
return redisService.keysValue(CacheKeys.getSystemColonyRedisSession(SysConst.EMPTY)).stream()
.map(item -> byteToSession(item.getBytes("session"))).collect(Collectors.toCollection(Lists::newArrayList));
}
/**
* session序列化问题处理
*
* @param session 会话
* @return sessionToByte
*/
public byte[] sessionToByte(Session session) {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
byte[] bytes = null;
try {
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(session);
bytes = bo.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return bytes;
}
/**
* 字节转session
*
* @param bytes 字节流
* @return Session
*/
public Session byteToSession(byte[] bytes) {
ByteArrayInputStream bi = new ByteArrayInputStream(bytes);
ObjectInputStream in;
SimpleSession session = null;
try {
in = new ObjectInputStream(bi);
session = (SimpleSession) in.readObject();
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
return session;
}
}
上面我是把会话缓存到redis里面了,如果大家有出现上面序列化问题可以私信我,这样如果我们把服务重启掉的话,session在redis里面缓存的时间还没有过期的话,就算是重启服务器都是不会有掉线需要重新登录等。
扫描二维码关注公众号,回复:
12936903 查看本文章