調(diào)教ChatGPT之『SpringBoot2中獲取所有會(huì)話列表』
1、背景
最近在分析一個(gè)性能問題,容器優(yōu)雅停機(jī)時(shí),停機(jī)時(shí)長超過 120 秒,導(dǎo)致容器被強(qiáng)殺了,經(jīng)過日志分析,發(fā)現(xiàn)停機(jī)時(shí)會(huì)話數(shù)量有 5000 多,在循環(huán)做 sessionDestroy 的時(shí)候耗時(shí)很長,所以打算寫一個(gè)方法打印一下所有session做深入分析。
2、答案
以前的話,肯定去百度一下,但現(xiàn)在有了ChatGPT,當(dāng)然是問ChatGPT更方便。但是,依然是一波三折,調(diào)教了一番寫給出最終的代碼。先給出最終的代碼,哪位看客想看調(diào)教過程,再往下看。
3、過程
下面是調(diào)教過程:
問:springboot2怎么獲取所有httpsession?
答:在Spring Boot 2中,可以通過以下代碼獲取所有的HTTP Session:
這個(gè)方法會(huì)獲取當(dāng)前Web應(yīng)用程序中的所有HTTP會(huì)話,包括那些由其他用戶創(chuàng)建的會(huì)話。需要注意的是,這個(gè)方法需要在一個(gè)已經(jīng)存在的HTTP請(qǐng)求的上下文中運(yùn)行,否則將會(huì)返回空列表。
問:我用的是tomcat9,servletcontext類沒有g(shù)etsessions()方法了,麻煩再幫忙改一下。
答:對(duì)不起,我的回答有誤。在Servlet API 4.0中,ServletContext類確實(shí)已經(jīng)刪除了getSessions()方法。在Tomcat 9中,你可以通過以下方式獲取所有會(huì)話:
上面的代碼使用了Tomcat 9的API,通過Context對(duì)象獲取到Manager,然后通過findSessions()方法返回所有的會(huì)話列表。請(qǐng)注意,上述代碼可能需要在Tomcat上下文中運(yùn)行,否則將會(huì)出現(xiàn)錯(cuò)誤。
問:servletcontext.getcontext()的出參是servletcontext,并不是context,麻煩再幫忙改一下。答:非常抱歉,我的前一個(gè)回答有誤。你是正確的,ServletContext.getContext()方法的返回類型是ServletContext,而不是Context。以下是修改后的代碼,用于獲取Tomcat 9中所有的HTTP Session:
上述代碼中,我們首先通過getServletContext()方法獲取到ServletContext對(duì)象,然后通過getContext("")方法獲取到當(dāng)前ServletContext所在的Context對(duì)象。最后通過getManager()方法獲取到Manager對(duì)象,并通過findSessions()方法返回所有的HTTP會(huì)話。再次感謝你的指正。
問:我用的是javax.servlet-api-4.0.1
答:好的,既然你在使用javax.servlet-api-4.0.1,那么你可以使用Servlet API 4.0中提供的新方法來獲取所有的HTTP Session。以下是修改后的代碼,用于獲取所有的HTTP Session:
上述代碼中,我們首先獲取到ServletContext對(duì)象,然后通過getAttributeNames()方法獲取所有的屬性名,然后通過getAttribute()方法獲取屬性值,最后判斷屬性值是否為HttpSession類型。如果是,則將其加入到結(jié)果集合中。請(qǐng)注意,雖然這種方法可以獲取所有的HTTP Session,但是可能會(huì)返回?zé)o效的HTTP Session。因?yàn)樵赟ervletContext中可能存儲(chǔ)了其他類型的對(duì)象,這些對(duì)象不一定是有效的HTTP Session。所以在使用這個(gè)方法時(shí)需要謹(jǐn)慎。
問:我用的是tomcat-embed-core:9.0.70
答:好的,既然你在使用tomcat-embed-core:9.0.70,那么你可以使用Tomcat 9的API來獲取所有的HTTP Session。以下是修改后的代碼,用于獲取所有的HTTP Session:
上述代碼中,我們首先通過Tomcat.getServletContext()方法獲取到ServletContext對(duì)象,然后通過getContext("")方法獲取當(dāng)前ServletContext所在的Context對(duì)象。最后通過getManager()方法獲取到Manager對(duì)象,并通過findSessions()方法返回所有的HTTP會(huì)話。
請(qǐng)注意,在使用tomcat-embed-core時(shí),你需要在代碼中手動(dòng)創(chuàng)建Tomcat實(shí)例,然后調(diào)用init()方法進(jìn)行初始化。同時(shí)也要注意,如果你在使用Spring Boot的話,可能需要在application.properties文件中添加以下配置:
這是因?yàn)镾pring Boot默認(rèn)會(huì)開啟Tomcat的訪問日志,可能會(huì)影響性能。
問:Request才有g(shù)etcontext方法
答:非常抱歉,我犯了一個(gè)錯(cuò)誤。你是對(duì)的,Request類有g(shù)etServletContext()方法,而不是getContext()方法。以下是修正后的代碼:
這個(gè)版本的代碼將會(huì)使用RequestContextHolder來獲取當(dāng)前請(qǐng)求的Request對(duì)象,然后使用getServletContext()方法獲取到ServletContext對(duì)象,最后遍歷所有的屬性,判斷是否為HttpSession類型。
非常感謝您的指正,希望這次能夠幫到您。
問:不要再提servletcontext了,servletrequestattributes.getrequest獲取到的是requestfacade,要用反射獲取真正的request,再用request.getcontext().getmanaget()獲取manager
答:非常抱歉,我犯了錯(cuò)誤。你是對(duì)的,ServletRequestAttributes獲取到的是ServletRequestFacade,而不是真正的ServletRequest。以下是修正后的代碼,使用反射獲取真正的ServletRequest對(duì)象:
在修正后的代碼中,我們使用反射來獲取RequestFacade內(nèi)部的request字段,這個(gè)字段是RequestFacade包裝的真正ServletRequest對(duì)象,我們通過這個(gè)對(duì)象來獲取ServletContext并最終獲取到Manager。
非常感謝您的指正,希望這次能夠幫到您。
問:request = (HttpServletRequest) field.get(requestFacade);錯(cuò)了,應(yīng)該是request = (Request) field.get(requestFacade);
答:非常感謝您的指正,您是對(duì)的。因?yàn)閛rg.apache.catalina.connector.RequestFacade內(nèi)部包裝的是org.apache.catalina.connector.Request對(duì)象,而不是javax.servlet.http.HttpServletRequest對(duì)象,所以我們需要使用org.apache.catalina.connector.Request對(duì)象來獲取ServletContext。
以下是修正后的代碼:
再次感謝您的指正,希望這次能夠幫到您。
問:不用封裝tomcathttpsession返回httpsession了,直接返回session即可。
答:如果您不需要對(duì)返回的Session對(duì)象做其他的操作,可以直接返回org.apache.catalina.session.StandardSession對(duì)象,因?yàn)樗呀?jīng)實(shí)現(xiàn)了HttpSession接口。
以下是修改后的代碼:
修改后的代碼中,getAllSessions方法直接返回List,省略了對(duì)StandardSession對(duì)象進(jìn)行包裝。由于StandardSession已經(jīng)實(shí)現(xiàn)了HttpSession接口,所以它可以直接作為HttpSession對(duì)象來使用。

到此,整個(gè)調(diào)教過程結(jié)束。在前幾個(gè)提問中,我希望通過增加關(guān)鍵詞的方式,嘗試讓ChatGPT根據(jù)關(guān)鍵詞進(jìn)行代碼優(yōu)化,但是效果不明顯。所以我把它提供的代碼在IDEA里自己翻源碼,其實(shí)這時(shí)候我已經(jīng)知道最終答案了,但是我希望ChatGPT寫出最終的代碼,所以我直接指出其中的錯(cuò)誤,ChatGPT居然真的理解我所指出的問題,并進(jìn)行代碼的優(yōu)化。進(jìn)過幾輪的優(yōu)化,最后給出了滿意的答案,這真的很厲害。
4、結(jié)語
智能機(jī)器人已經(jīng)是一個(gè)不可逆的發(fā)展趨勢(shì),那些大佬們所擔(dān)心的人類文明問題,不是我們這些農(nóng)民所能左右的,既來之則安之,把它用好才不會(huì)被社會(huì)淘汰。