Skip to content

Commit

Permalink
feat: docean support redis session (XiaoMi#891)
Browse files Browse the repository at this point in the history
  • Loading branch information
shanwb committed Sep 3, 2024
1 parent bd03aa7 commit 5958947
Show file tree
Hide file tree
Showing 17 changed files with 354 additions and 55 deletions.
34 changes: 34 additions & 0 deletions jcommon/docean-plugin/docean-plugin-redisSession/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>run.mone</groupId>
<artifactId>docean-plugin</artifactId>
<version>1.6.0-jdk21-SNAPSHOT</version>
</parent>

<artifactId>docean-plugin-redisSession</artifactId>

<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>run.mone</groupId>
<artifactId>docean</artifactId>
<version>1.6.1-jdk21-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>run.mone</groupId>
<artifactId>docean-plugin-redis</artifactId>
<version>1.6.0-jdk21-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright 2020 Xiaomi
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package run.mone.docean.plugin.redissession;

import com.xiaomi.youpin.docean.Ioc;
import com.xiaomi.youpin.docean.anno.DOceanPlugin;
import com.xiaomi.youpin.docean.plugin.IPlugin;
import com.xiaomi.youpin.docean.plugin.redis.Redis;
import lombok.extern.slf4j.Slf4j;

import java.util.Set;

/**
* @author shanwb
* @date 2024-09-03
*/
@DOceanPlugin(order = 101)
@Slf4j
public class RedisSessionPlugin implements IPlugin {


@Override
public void init(Set<? extends Class<?>> classSet, Ioc ioc) {
Redis redis = ioc.getBean(Redis.class);
if (null == redis) {
log.error("redis can not be empty");
}
RedisSessionStore redisSessionStore = new RedisSessionStore(redis);
ioc.putBean("ClusterSessionStore", redisSessionStore);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package run.mone.docean.plugin.redissession;

import com.google.gson.Gson;
import com.xiaomi.youpin.docean.mvc.session.DefaultHttpSession;
import com.xiaomi.youpin.docean.mvc.session.HttpSession;
import com.xiaomi.youpin.docean.mvc.session.ISessionStore;
import com.xiaomi.youpin.docean.plugin.redis.Redis;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;

/**
* @author shanwb
* @date 2024-09-03
*/
@Slf4j
public class RedisSessionStore implements ISessionStore {

private static final String SESSION_PREFIX = "DOCEAN_SESSION_";

private static final int SESSION_EXPIRE_SECONDS = 3600; // 默认60分钟过期

private final static Gson gson = new Gson();

private Redis redis;

public RedisSessionStore(Redis redis) {
this.redis = redis;
}

@Override
public void put(String sessionId, HttpSession session) {
try {
String key = SESSION_PREFIX + sessionId;
String value = gson.toJson(session);
redis.set(key, value, SESSION_EXPIRE_SECONDS);
} catch (Exception e) {
log.error("Error putting session to redis", e);
}
}

@Override
public void remove(String sessionId) {
try {
String key = SESSION_PREFIX + sessionId;
redis.del(key);
} catch (Exception e) {
log.error("Error removing session from redis", e);
}
}

@Override
public List<String> sessionIdList() {
return new ArrayList<>();
}

@Override
public HttpSession get(String sessionId) {
try {
String key = SESSION_PREFIX + sessionId;
String value = redis.get(key);
if (value == null) {
return null;
}
return gson.fromJson(value, DefaultHttpSession.class);
} catch (Exception e) {
log.error("Error getting session from redis", e);
return null;
}
}

@Override
public HttpSession getAndRefresh(String sessionId) {
try {
String key = SESSION_PREFIX + sessionId;
String value = redis.get(key);
if (value == null) {
return null;
}
DefaultHttpSession session = gson.fromJson(value, DefaultHttpSession.class);
redis.expire(key, SESSION_EXPIRE_SECONDS);
return session;
} catch (Exception e) {
log.error("Error getting session from redis", e);
return null;
}
}

@Override
public boolean containsKey(String sessionId) {
try {
String key = SESSION_PREFIX + sessionId;
return redis.exists(key);
} catch (Exception e) {
log.error("Error checking session existence in redis", e);
return false;
}
}
}
1 change: 1 addition & 0 deletions jcommon/docean-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
<module>docean-plugin-es-antlr4</module>
<module>docean-plugin-storage</module>
<module>docean-plugin-junit</module>
<module>docean-plugin-redisSession</module>
</modules>
<dependencies>
<dependency>
Expand Down
18 changes: 17 additions & 1 deletion jcommon/docean/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,20 @@
processing, bean initialization, and loading into the container.
The plugin package has added extended support for some commonly used dependencies in projects, such as nacos, dubbo,
mybatis, and so on.
* rate limited or exceeded quota
* rate limited or exceeded quota

#Feature

## session用法
### 单机session使用
需要在ioc中加入一个bean[LocalSessionStore.java](src/main/java/com/xiaomi/youpin/docean/mvc/session/impl/LocalSessionStore.java)
ioc init时,添加扫描路径"com.xiaomi.youpin.docean.mvc.session"

### 分布式事务
1.工程中引入两个plugin:[docean-plugin-redis](../docean-plugin/docean-plugin-redis)[docean-plugin-redisSession](../docean-plugin/docean-plugin-redisSession)
2.添加配置,开启分布式配置:ioc.putBean("$cluster-session", "true")





14 changes: 8 additions & 6 deletions jcommon/docean/src/main/java/com/xiaomi/youpin/docean/Mvc.java
Original file line number Diff line number Diff line change
Expand Up @@ -81,17 +81,19 @@ private Mvc(Ioc ioc) {
}

private void setConfig(Ioc ioc) {
this.mvcConfig.setAllowCross(Boolean.valueOf(ioc.getBean(MvcConst.ALLOW_CROSS_DOMAIN, MvcConst.FALSE)));
this.mvcConfig.setDownload(Boolean.valueOf(ioc.getBean(MvcConst.MVC_DOWNLOAD, MvcConst.FALSE)));
this.mvcConfig.setUseCglib(Boolean.valueOf(ioc.getBean(MvcConst.CGLIB, MvcConst.TRUE)));
this.mvcConfig.setAllowCross(Boolean.parseBoolean(ioc.getBean(MvcConst.ALLOW_CROSS_DOMAIN, MvcConst.FALSE)));
this.mvcConfig.setDownload(Boolean.parseBoolean(ioc.getBean(MvcConst.MVC_DOWNLOAD, MvcConst.FALSE)));
this.mvcConfig.setUseCglib(Boolean.parseBoolean(ioc.getBean(MvcConst.CGLIB, MvcConst.TRUE)));

this.mvcConfig.setOpenStaticFile(Boolean.valueOf(ioc.getBean(MvcConst.OPEN_STATIC_FILE, MvcConst.FALSE)));
this.mvcConfig.setOpenStaticFile(Boolean.parseBoolean(ioc.getBean(MvcConst.OPEN_STATIC_FILE, MvcConst.FALSE)));
this.mvcConfig.setStaticFilePath(ioc.getBean(MvcConst.STATIC_FILE_PATH, MvcConst.EMPTY));

this.mvcConfig.setResponseOriginalValue(Boolean.valueOf(ioc.getBean(MvcConst.RESPONSE_ORIGINAL_VALUE, MvcConst.FALSE)));
this.mvcConfig.setResponseOriginalValue(Boolean.parseBoolean(ioc.getBean(MvcConst.RESPONSE_ORIGINAL_VALUE, MvcConst.FALSE)));
this.mvcConfig.setPoolSize(Integer.valueOf(ioc.getBean(MvcConst.MVC_POOL_SIZE, String.valueOf(MvcConst.DEFAULT_MVC_POOL_SIZE))));
this.mvcConfig.setVirtualThread(Boolean.valueOf(ioc.getBean(MvcConst.VIRTUAL_THREAD, MvcConst.TRUE)));
this.mvcConfig.setVirtualThread(Boolean.parseBoolean(ioc.getBean(MvcConst.VIRTUAL_THREAD, MvcConst.TRUE)));
this.mvcConfig.setResponseOriginalPath(ioc.getBean(MvcConst.RESPONSE_ORIGINAL_PATH, ""));
this.mvcConfig.setClusterSession(Boolean.parseBoolean(ioc.getBean(MvcConst.CLUSTER_SESSION, MvcConst.FALSE)));

ioc.publishEvent(new Event(EventType.mvcBegin, this.mvcConfig));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,6 @@ public class MvcConfig implements Serializable {
*/
private String responseOriginalPath;

private boolean clusterSession;

}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ public class MvcContext {
*/
private boolean allowCross;

/**
* cluster session
*/
private boolean clusterSession;

public HttpSession session() {
if (null == session) {
this.session = HttpSessionManager.getSession(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public MvcRunnable(Mvc mvc, HttpServerConfig config, ChannelHandlerContext ctx,
this.context.setVirtualThread(mvc.getMvcConfig().isVirtualThread());
this.context.setPath(path);
this.context.setAllowCross(mvc.getMvcConfig().isAllowCross());
this.context.setClusterSession(mvc.getMvcConfig().isClusterSession());
this.request.setMethod(method);
this.request.setPath(path);
this.request.setBody(body);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public abstract class MvcConst {

public static final String RESPONSE_ORIGINAL_PATH = "$response-original-path";

public static final String CLUSTER_SESSION = "$cluster-session";

public static final int DEFAULT_MVC_POOL_SIZE = 200;

public static ScopedValue<MvcContext> MVC_CONTEXT = ScopedValue.newInstance();
Expand Down
Loading

0 comments on commit 5958947

Please sign in to comment.