最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JAVA?SSE接口開發(fā)中的Spring?Security與異步線程池配置方法

 更新時(shí)間:2025年12月22日 14:42:33   作者:布伽思索  
本文詳細(xì)描述了在使用SpringSecurity和異步線程池進(jìn)行SSE接口開發(fā)時(shí)遇到的兩個(gè)問題:AccessDeniedException異常和SimpleAsyncTaskExecutor警告,文章還介紹了線程池參數(shù)的科學(xué)估算方法,并適用于SpringBoot/SpringMVC的SSE接口生產(chǎn)環(huán)境配置,感興趣的朋友一起看看吧

JAVA SSE接口開發(fā)中的Spring Security與異步線程池

本文記錄了SSE(Server-Sent Events)接口開發(fā)場景中遇到的兩個(gè)問題——Spring Security的AccessDeniedException異常SimpleAsyncTaskExecutor生產(chǎn)環(huán)境警告,提供從根源分析到落地實(shí)現(xiàn)的完整解決方案,同時(shí)附上線程池參數(shù)的科學(xué)估算方法,適用于Spring Boot/Spring MVC的SSE接口生產(chǎn)環(huán)境配置。

一、SSE接口的Spring Security權(quán)限異常解析與解決

1. 異常根源:異步請求的二次權(quán)限校驗(yàn)沖突

當(dāng)使用注解中使用了produces = MediaType.TEXT_EVENT_STREAM_VALUE定義SSE接口時(shí)(列如:@PostMapping(value = “/chat”,produces = MediaType.TEXT_EVENT_STREAM_VALUE)),會觸發(fā)Servlet異步處理機(jī)制,異常產(chǎn)生的完整鏈路如下:

  • 客戶端發(fā)起請求,Spring Security攔截初始請求,權(quán)限校驗(yàn)通過后進(jìn)入業(yè)務(wù)邏輯,通過SseEmitter向客戶端流式發(fā)送數(shù)據(jù);
  • 當(dāng)SseEmitter調(diào)用complete()方法完成數(shù)據(jù)發(fā)送后,Servlet容器會觸發(fā)一次DispatcherType.ASYNC類型的內(nèi)部轉(zhuǎn)發(fā),這是Servlet規(guī)范的異步回調(diào)機(jī)制;
  • Spring Security默認(rèn)攔截所有類型請求(包括ASYNC),但此時(shí)SSE響應(yīng)已提交,且異步轉(zhuǎn)發(fā)的請求上下文可能不完整(如請求路徑信息缺失),導(dǎo)致權(quán)限校驗(yàn)失敗并拋出AccessDeniedException,而響應(yīng)已無法修改,最終僅能在日志中記錄異常。

核心矛盾:SSE的異步特性與Spring Security默認(rèn)攔截規(guī)則的生命周期沖突,非用戶真實(shí)權(quán)限不足問題。

2. 解決方案:精準(zhǔn)排除異步請求的權(quán)限校驗(yàn)

核心思路:通過.dispatcherTypeMatchers(DispatcherType.ASYNC).permitAll() 設(shè)置保留初始請求的權(quán)限校驗(yàn),讓Spring Security忽略ASYNC類型的異步轉(zhuǎn)發(fā)請求,兼顧安全性與功能正確性。

2.1 安全配置實(shí)現(xiàn)

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
        return httpSecurity
                // CSRF禁用,因?yàn)椴皇褂胹ession
                .csrf(AbstractHttpConfigurer::disable)
                // 禁用HTTP響應(yīng)標(biāo)頭
                .headers(header -> header.cacheControl(HeadersConfigurer.CacheControlConfig::disable).frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
                // 認(rèn)證失敗處理類
                .exceptionHandling(exception -> exception.authenticationEntryPoint(unauthorizedHandler))
                // 基于token,所以不需要session
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                // 注解標(biāo)記允許匿名訪問的url
                .authorizeHttpRequests((requests) -> {
                    permitAllUrl.getUrls().forEach(url -> requests.requestMatchers(url).permitAll());
                    // 對于登錄login 注冊register 驗(yàn)證碼captchaImage 允許匿名訪問
                    requests.requestMatchers("/login", "/register", "/captchaImage").permitAll()
                            .dispatcherTypeMatchers(DispatcherType.ASYNC).permitAll() //新增設(shè)置*
                            // 靜態(tài)資源,可匿名訪問
                            .requestMatchers(HttpMethod.GET, "/", "/*.html", "/**.html", "/**.css", "/**.js", "/profile/**").permitAll()
                            .requestMatchers("/webjars/**", "/druid/**").permitAll()
                            // 除上面外的所有請求全部需要鑒權(quán)認(rèn)證
                            .anyRequest().authenticated();
                })
                // 添加Logout filter
                .logout(logout -> logout.logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler))
                // 添加JWT filter
                .addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
                // 添加CORS filter
                .addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class)
                .addFilterBefore(corsFilter, LogoutFilter.class).build();
    }
}

2.2 其他情況

    也可以使用`.requestMatchers("/test").permitAll()`開放SSE接口!但是該方式會放棄網(wǎng)關(guān)層面的權(quán)限控制,需在業(yè)務(wù)代碼中手動(dòng)校驗(yàn)身份,極易引發(fā)安全問題。

二、異步線程池警告的解決:生產(chǎn)級配置

1. 警告原因:默認(rèn)執(zhí)行器的資源隱患

Spring MVC處理SSE等異步請求時(shí),默認(rèn)使用SimpleAsyncTaskExecutor,其核心缺陷是無線程復(fù)用機(jī)制——每次請求都會創(chuàng)建新線程。在高并發(fā)場景下,大量線程的創(chuàng)建與銷毀會耗盡CPU和內(nèi)存資源,因此Spring會拋出明確的生產(chǎn)環(huán)境使用警告。

2. 解決方案:自定義線程池實(shí)現(xiàn)線程復(fù)用

通過配置ThreadPoolTaskExecutor(基于線程池的執(zhí)行器),并通過WebMvcConfigurer將其綁定到Spring MVC的異步支持,實(shí)現(xiàn)線程復(fù)用與資源管控。

2.1 線程池配置類

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
public class AsyncWebMvcConfig implements WebMvcConfigurer {
    /**
     * 配置Spring MVC異步請求的任務(wù)執(zhí)行器
     */
    @Override
    public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
        configurer.setTaskExecutor(mvcAsyncTaskExecutor()); // 綁定自定義線程池
        configurer.setDefaultTimeout(60_000L); // 可選:SSE會話超時(shí)時(shí)間(毫秒),按需調(diào)整
    }
    /**
     * 定義生產(chǎn)級線程池Bean
     */
    @Bean(name = "mvcAsyncTaskExecutor")
    public Executor mvcAsyncTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        int cpuCores = Runtime.getRuntime().availableProcessors(); // 動(dòng)態(tài)獲取CPU核心數(shù)
        // 核心參數(shù)配置
        executor.setCorePoolSize(cpuCores * 2); // 核心線程數(shù):IO密集型任務(wù)推薦CPU核心數(shù)*2
        executor.setMaxPoolSize(cpuCores * 5);  // 最大線程數(shù):高峰期彈性擴(kuò)容上限
        executor.setQueueCapacity(100);         // 任務(wù)隊(duì)列:緩沖瞬時(shí)突發(fā)流量
        executor.setThreadNamePrefix("sse-async-"); // 線程名前綴:便于日志追蹤和監(jiān)控
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 拒絕策略
        executor.setKeepAliveSeconds(60); // 空閑線程存活時(shí)間:超過核心線程數(shù)的空閑線程60秒后銷毀
        executor.initialize(); // 初始化執(zhí)行器
        return executor;
    }
}

2.2 服務(wù)層使用自定義線程池

若在服務(wù)層使用@Async注解實(shí)現(xiàn)異步邏輯,需指定自定義線程池的Bean名稱,避免使用默認(rèn)執(zhí)行器:

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class SseAsyncService {
    // 明確指定使用自定義線程池
    @Async("mvcAsyncTaskExecutor")
    public void handleSseMessage(String message) {
        // SSE相關(guān)的異步業(yè)務(wù)邏輯
        System.out.println("處理SSE消息:" + message);
    }
}

三、線程池核心參數(shù)的科學(xué)估算與調(diào)優(yōu)

線程池的核心參數(shù)(corePoolSize、maxPoolSize、queueCapacity)直接影響接口性能,需結(jié)合任務(wù)類型(CPU密集/IO密集)和系統(tǒng)資源科學(xué)配置,以下為可落地的估算方法與調(diào)優(yōu)思路。

1. 核心參數(shù)估算邏輯

參數(shù)名稱估算依據(jù)參考公式/建議值
corePoolSize(核心線程數(shù))任務(wù)類型決定CPU利用率,避免線程切換損耗CPU密集型:CPU核心數(shù) + 1IO密集型(如SSE):CPU核心數(shù) * 2
maxPoolSize(最大線程數(shù))系統(tǒng)高峰期的彈性處理能力,避免資源過載公式:(CPU核心數(shù) * 目標(biāo)CPU使用率) / (1 - 阻塞系數(shù))經(jīng)驗(yàn)值:核心線程數(shù)的2-5倍(SSE推薦3-5倍)
queueCapacity(隊(duì)列容量)緩沖瞬時(shí)流量,平衡響應(yīng)延遲與任務(wù)堆積風(fēng)險(xiǎn)經(jīng)驗(yàn)值:100-500(過大易導(dǎo)致延遲,過小易觸發(fā)拒絕策略)

關(guān)鍵概念:阻塞系數(shù)指任務(wù)執(zhí)行中IO等待(如網(wǎng)絡(luò)請求、數(shù)據(jù)庫操作)的時(shí)間占比,SSE接口為典型IO密集型任務(wù),阻塞系數(shù)約0.8-0.9。

2. 生產(chǎn)環(huán)境調(diào)優(yōu)步驟

  • 基準(zhǔn)測試:低負(fù)載下運(yùn)行接口,驗(yàn)證功能正常且線程池?zé)o異常;
  • 壓力測試:使用JMeter、Gatling等工具模擬高并發(fā),逐步提升并發(fā)用戶數(shù)(如從100到1000);
  • 核心監(jiān)控指標(biāo):聚焦以下指標(biāo)判斷配置合理性:
  • 系統(tǒng)資源:CPU使用率(建議穩(wěn)定在60%-80%)、內(nèi)存占用(無持續(xù)增長);
  • 線程池狀態(tài):活躍線程數(shù)(是否頻繁接近maxPoolSize)、隊(duì)列任務(wù)數(shù)(是否持續(xù)高位)、任務(wù)拒絕次數(shù)(需為0);
  • 接口性能:平均響應(yīng)時(shí)間(無明顯波動(dòng))、錯(cuò)誤率(低于0.1%)。
  • 參數(shù)調(diào)整策略
  • CPU瓶頸早現(xiàn)但吞吐量低:核心線程數(shù)過高,適當(dāng)下調(diào);
  • 活躍線程達(dá)上限且隊(duì)列滿:適度提升maxPoolSize和queueCapacity;
  • 任務(wù)頻繁被拒絕:需從服務(wù)擴(kuò)容(增加CPU/內(nèi)存)或業(yè)務(wù)優(yōu)化(拆分任務(wù))層面解決。

3. 拒絕策略選擇

當(dāng)線程池和隊(duì)列均滿時(shí),拒絕策略決定新任務(wù)的處理方式,SSE接口推薦優(yōu)先級如下:

  • CallerRunsPolicy(推薦):由提交任務(wù)的線程(如Tomcat工作線程)直接執(zhí)行任務(wù),產(chǎn)生自然背壓,減緩請求提交速度,避免任務(wù)丟失;
  • DiscardOldestPolicy:僅當(dāng)任務(wù)允許丟棄時(shí)使用,丟棄隊(duì)列中最舊的任務(wù)后接收新任務(wù);
  • AbortPolicy(默認(rèn)):直接拋出RejectedExecutionException,需結(jié)合業(yè)務(wù)捕獲處理,否則會導(dǎo)致接口報(bào)錯(cuò)。

四、核心結(jié)論與實(shí)踐建議

  • SSE接口的AccessDeniedException:核心解決手段是通過NegatedRequestMatcher排除ASYNC類型請求的權(quán)限校驗(yàn),而非開放接口權(quán)限;
  • 異步線程池警告:必須自定義ThreadPoolTaskExecutor實(shí)現(xiàn)線程復(fù)用,SimpleAsyncTaskExecutor嚴(yán)禁用于生產(chǎn)環(huán)境;
  • 參數(shù)配置核心:以CPU核心數(shù)為基準(zhǔn),區(qū)分任務(wù)類型(SSE為IO密集型),結(jié)合壓測與監(jiān)控動(dòng)態(tài)調(diào)優(yōu);
  • 監(jiān)控優(yōu)先:為線程池設(shè)置清晰的線程名前綴,便于通過APM工具(如SkyWalking)監(jiān)控線程狀態(tài),快速定位問題。

(注:文檔部分內(nèi)容可能由 AI 生成)

到此這篇關(guān)于JAVA SSE接口開發(fā)中的Spring Security與異步線程池配置的文章就介紹到這了,更多相關(guān)Spring Security與異步線程池配置內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

肇庆市| 盐源县| 通山县| 黄浦区| 尖扎县| 满洲里市| 安岳县| 邯郸县| 阳江市| 抚松县| 扎囊县| 洪洞县| 西华县| 永德县| 友谊县| 蒲城县| 辉南县| 南平市| 科技| 泰州市| 调兵山市| 武夷山市| 黄大仙区| 平陆县| 乡宁县| 台中市| 项城市| 怀远县| 密山市| 府谷县| 社旗县| 哈密市| 孟村| 吉木乃县| 论坛| 五华县| 元氏县| 贵南县| 浮山县| 浠水县| 达孜县|