完美解决JFinal-undertow的分布式session方案

想来也不少伙伴像我一样,一直在找完美的JFinal-undertow分布式session解决方案。之前有伙伴使用拦截器的方式曲线救国去实现分布式session,虽然确实也能实现,但个中滋味,只有自己知道。

经过一番研究,在@JFinal和@SuperEric的帮助下,完美解决了JFinal-undertow的分布式session问题。

首先,去github上下一个别人扩展好的一个RedisSessionManager,下载地址:

https://github.com/coat/undertow-redis-session

这上面下的,只需要使用到里面的RedisSessionManager这个一个类文件。其他的都可以不要。

我是用这个文件,然后自己又扩展了一些功能,这里就不再献丑了。

然后再创建一个RedisSessionManagerFactory类,代码如下:

import java.net.URI;

import io.undertow.server.session.SessionCookieConfig;
import io.undertow.server.session.SessionManager;
import io.undertow.servlet.api.Deployment;
import io.undertow.servlet.api.SessionManagerFactory;

public class RedisSessionManagerFactory implements SessionManagerFactory {
	private URI redisUri;
	public RedisSessionManagerFactory(URI redisUri) {
		this.redisUri = redisUri;
	}

	@Override
	public SessionManager createSessionManager(Deployment arg0) {
		SessionCookieConfig sessionConfig = new SessionCookieConfig();
        sessionConfig.setCookieName("session");
		return new RedisSessionManager(redisUri, sessionConfig);
	}

}

最后在MainConfig里的main方法里这么写:

public static void main(String[] args) {
		UndertowServer.create(MainConfig.class,"undertow.properties")
		.configWeb(builder -> {
			Prop p = PropKit.use(ConstantConfig.CONFIG_FILE).appendIfExists(ConstantConfig.CONFIG_FILE_PRO);
			String deployMode = p.get("deploy.mode", ConstantConfig.DEPLOY_NORMAL);
			String sessionStorage = p.get("deploy.session.storage", "");
			boolean isDistributed = ConstantConfig.DEPLOY_DISTRIBUTED.equals(deployMode);
			//如果是分布式部署,并且session被配置到redis
			if(isDistributed && "redis".equals(sessionStorage)) {
				try {
					String redisHost = p.get("deploy.session.redis.host", "127.0.0.1");
					String redisPort = p.get("deploy.session.redis.port", "6379");
					String redisDb = p.get("deploy.session.redis.db", "0");
					String redisUri = "redis://"+redisHost+":"+redisPort+"/"+redisDb;
					builder.getDeploymentInfo().setSessionManagerFactory(new RedisSessionManagerFactory(new URI(redisUri)));
				} catch (URISyntaxException e) {
					e.printStackTrace();
				}
			}
            // 配置WebSocket需使用ServerEndpoint注解
            builder.addWebSocketEndpoint("cn.york.common.websocket.WebSocketEndpoint");
        })
		.start();
	}

这里只是我这里写的方法,因为我要判断是单机部署,还是分布式部署。这里仅供参考。主要是这句代码:

builder.getDeploymentInfo().setSessionManagerFactory(new RedisSessionManagerFactory(new URI(redisUri)));

先把你的redis启动起来,然后再启动你的程序,打开浏览器,看看是不是一切都清爽了。

使用这种方法,你之前的getSessionAttr,setSessionAttr等一系列操作完全不用修改。你就当是单机一样使用就行了。

再次体现了JFinal的开发初衷:极简!

评论区

JFinal

2021-03-02 15:09

居然知道 UndertowServer.configWeb 中有一个
builder.getDeploymentInfo().setSessionManagerFactory(...)

很有探索精神,收藏点赞,以后有用

杜福忠

2021-03-02 15:27

收藏+点赞!今年要做个大项目,这不就刚好就用上了嘛

zeroabc

2021-03-02 17:07

好东西!!

haojay

2021-03-02 21:13

@JFinal 搞个一键双联,长按点赞自动收藏

爱做饭的开饭

2021-03-02 23:36

支持,希望JFinal有后续支持!

山东小木

2021-03-03 12:31

海哥

2021-03-03 13:54

建议还是参考 JBoot 的方式,通过 Handler 去做,这样才能做到让 JFinal 部署在不同的容器里,Undertow、tomcat、jetty 或者其他任何容器随意切换。

pobaby

2021-03-03 13:55

帅气

prelove

2021-03-03 15:01

JBoot用redis做分布式缓存确实很方便了

flb_xiaotian

2021-03-03 17:17

山东小木

2021-03-04 21:31

zzutligang

2021-03-05 10:57

@海哥 JBoot已经做得很好了。我也从JBoot里学了很多东西。只是我这里自己封装了一套方便自己开发使用。自从换到undertow上,也就不再考虑其他web容器了。只要能让我尽快打完收工,尽早回家陪“女朋友”就行了。^_^

烈火123

2021-03-06 18:48

厉害

一路走来

2021-03-08 11:44

都搞分布式了,为什么还会用到session?

zzutligang

2021-03-08 15:36

@一路走来 web应用如果部署成多实例实现负载均衡和故障转移,肯定就需要使用分布式session了啊。登录可以使用cookie,也可以集成单点登录,但也会需要这种分布式session的。并不是分布式都是做api接口的。