자바 는 Deferred Result 를 이용 하여 http 폴 링 실시 간 으로 데이터 인 터 페 이 스 를 되 돌려 줍 니 다.

오늘 이 글 은 어렵 지 않 습 니 다.사실은 제 가 줄곧 마음속 에 품 고 있 는 의문 을 풀 어 주 는 것 입 니 다.이 렇 습 니 다.앞서 심 검 5·8 기술 위원회 의장 의 공중 번호 구조 사의 길 을 본 글 은 http 가 tcp 처럼 실시 간 으로 정 보 를 받 는 방법 입 니 다.그 중의 한 방안 은 http 짧 은 연결 폴 링 방식 으로'위장 연결'을 실현 하 는 것 입 니 다.그러나 폴 링 에 대한 우리 의 첫 반응 은 분명 지연 되 었 을 것 이다.그러나 제목 은 실시 간 이 라 고 하지 않 았 느 냐?물론 우 리 는 폴 링 의 시간 을 줄 일 수 있 습 니 다.이런 대부분의 시간의 폴 링 호출 은 말 하지 않 아 도 메시지 가 돌아 오지 않 아 서버 자원 의 낭 비 를 초래 할 수 있 습 니 다.폴 링 시간 이 아무리 짧 아 도 시간 이 지연 되 기 때문에 가짜 실시 간 입 니까?어쨌든 일반적인 소식 은 3,5 초,심지어 10 초 8 초 1 분 지연 되 었 습 니 다.여러분 도 개의 치 않 고 상대방 의 귀환 이 느리다 고 생각 할 뿐 그렇지 않 습 니 다.이것 은 우리 프로그래머 의 냄비 입 니 다.그런데 http 는 정말 실시 간 으로 실현 되 지 않 습 니까?심 검 선생님 은 웹 im 과 웹 서버 사이 에 http 연결 을 만들어 메시지 채널 로 사용 하 는 방법 을 제시 했다.이 연결 은 http 메시지 연결 이 라 고 한다.그리고 다음 과 같이 처리 합 니 다.
1.메시지 가 도착 하지 않 을 때 이 http 메시지 연결 은 다 져 지고 되 돌아 오지 않 습 니 다.http 는 짧 은 연결 이기 때문에 이 http 메시지 연결 은 최대 90 초 까지 다 져 지면 끊 깁 니 다(이것 은 브 라 우 저 나 웹 서버 의 행동 입 니 다).
2.1 의 경우 http 메시지 연결 이 끊 기 면 http 메시지 연결 을 다시 시작 합 니 다.
이 때 1 과 2 의 협조 하에 브 라 우 저 와 웹 서버 사이 에 영원히 메시지 가 연 결 됩 니 다.그리고 또 하나의 상황 이 있 습 니 다.
3.메 시 지 를 받 을 때마다 이 메시지 연결 은 즉시 메 시 지 를 브 라 우 저 페이지 로 가 져 오고 돌아 오 면 http 메시지 연결 을 다시 시작 합 니 다.
이렇게 하면 http 엔 드 로 폴 링 을 연결 하 는 방식 으로 실시 간 으로 메 시 지 를 받 을 수 있 습 니 다.그러나 설명 이 필요 한 것 은 사실 또 하나의 상황 이 있 습 니 다.메시지 가 도 착 했 을 때 이전 http 메시지 연결 이 되 돌아 오고 있 습 니 다.즉,두 번 째 상황 에서 갑자기 메시지 가 왔 습 니 다.이때 http 메시지 연결 을 사용 할 수 없습니다.이론 적 으로 http 메시지 연결 의 귀환 은 순간 적 이 고 메시지 연결 이 나타 날 확률 이 매우 낮 지만 머 피 법칙 에 따 르 면 이런 상황 이 반드시 나타 날 것 이라는 것 을 알 고 있 습 니 다.그래서 이런 상황 에서 우 리 는 소식 을 잠시 메시지 풀 에 저장 할 수 있 습 니 다.다음 소식 연결 이 도착 한 후에 기다 릴 필요 가 없습니다.직접 메시지 풀 에 가서 소식 을 찾 고 소식 을 가 져 올 수 있 습 니 다.그리고 즉시 새로운 메시지 연결 을 만 드 는 것 으로 돌아 가면 됩 니 다.
그러나 이상 은 오늘 이 글 의 중점 이 아니 라 오늘 이 글 의 제목 과 아무런 관계 가 없다.중요 한 것 은 심 검 선생님 의 이 글 을 본 후에 저 는 첫 번 째 단계 에서 어떻게 다 지 느 냐 는 의문 이 있 었 습 니 다.sleep 할 수 없 잖 아 요.얼마나 우아 하지 않 아 요.비슷 한 수 요 를 겪 어 본 적 이 없다 고 생각 했 기 때문에 몇 년 동안 저도 이 문 제 를 깊이 연구 하지 못 했 습 니 다.하지만 마음 속 으로 는 기억 하고 있 습 니 다.얼마 전에 마 병사 교육 의 공개 수업 을 들 었 습 니 다.그때 비슷 한 문 제 를 다시 이야기 할 때 http 의 연결 을 다 지 는 것 을 언급 했 습 니 다.(구체 적 으로 어떤 문제 인지 기억 이 나 지 않 습 니 다)당시 수업 시간 에 선생님 께 서 어떻게 실현 되 는 지 말씀 하지 않 으 셨 지만 평론 가 는 어떻게 다 져 서 돌아 오지 않 는 지 물 어 봤 습 니 다.그 다음 에 한 친구 가 Deferred Result 로 수업 이 끝 난 후에 자 료 를 찾 아 봤 는데 과연 가능 하 다 고 답 했다.다음 과 같이 실 현 된 노트 이기 때문에 이것 이 중점 이 고 이런 의문 이 있 는 친구 들 에 게 도 도움 이 되 었 으 면 좋 겠 다 고 말 했다.
1.메 시 지 는 실체 클래스 로 되 돌아 갑 니 다.여러분 은 실제 상황 에 따라 스스로 정의 하면 됩 니 다.

package cn.bridgeli.deferredresulttest.entity;
 
import lombok.Data;
import lombok.Getter;
 
/**
 * @author bridgeli
 */
@Data
public class DeferredResultResponse {
    private Integer code;
    private String msg;
 
    public enum Msg {
        TIMEOUT("  "),
        FAILED("  "),
        SUCCESS("  ");
 
        @Getter
        private String desc;
 
        Msg(String desc) {
            this.desc = desc;
        }
    }
}
2.controller 인터페이스:

package cn.bridgeli.deferredresulttest.controller;
 
import cn.bridgeli.deferredresulttest.entity.DeferredResultResponse;
import cn.bridgeli.deferredresulttest.service.DeferredResultService;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
 
import javax.annotation.Resource;
 
 
/**
 * @author bridgeli
 */
@RestController
@RequestMapping(value = "/deferred-result")
public class DeferredResultController {
 
    @Resource
    private DeferredResultService deferredResultService;
 
    /**
     *       ,      
     *         requestId    
     */
    private final String requestId = "test";
 
 
    @GetMapping(value = "/get")
    public DeferredResult<DeferredResultResponse> get(@RequestParam(value = "timeout", required = false, defaultValue = "10000") Long timeout) {
        DeferredResult<DeferredResultResponse> deferredResult = new DeferredResult<>(timeout);
 
        deferredResultService.process(requestId, deferredResult);
 
        return deferredResult;
    }
 
    /**
     *   DeferredResult   result  ,      
     *
     * @param desired
     * @return
     */
    @GetMapping(value = "/result")
    public String settingResult(@RequestParam(value = "desired", required = false, defaultValue = "  ") String desired) {
        DeferredResultResponse deferredResultResponse = new DeferredResultResponse();
        if (DeferredResultResponse.Msg.SUCCESS.getDesc().equals(desired)) {
            deferredResultResponse.setCode(HttpStatus.OK.value());
            deferredResultResponse.setMsg(desired);
        } else {
            deferredResultResponse.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
            deferredResultResponse.setMsg(DeferredResultResponse.Msg.FAILED.getDesc());
        }
        deferredResultService.settingResult(requestId, deferredResultResponse);
 
        return "Done";
    }
}
그 중에서/get 인 터 페 이 스 는 심 검 선생님 이 말씀 하신 메시지 연결 을 모 의 한 것 입 니 다./result 인 터 페 이 스 는 새로운 소식 이 온 것 을 모 의 한 다음/get 인 터 페 이 스 는 바로 돌아 갑 니 다.주요 한 것 은 requestId 입 니 다.실제 프로젝트 에서 같은 것 을 사용 할 수 없습니다.그렇지 않 으 면 문제 가 발생 할 수 있 습 니 다.이 테스트 를 통 해 알 수 있 고 원인 도 쉽게 생각 할 수 있 습 니 다.
3.서비스 실현:

package cn.bridgeli.deferredresulttest.service;
 
import cn.bridgeli.deferredresulttest.entity.DeferredResultResponse;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.async.DeferredResult;
 
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
 
/**
 * @author bridgeli
 */
@Service
public class DeferredResultService {
 
    private Map<String, Consumer<DeferredResultResponse>> taskMap;
 
    public DeferredResultService() {
        taskMap = new ConcurrentHashMap<>();
    }
 
    /**
     *    id setResult  
     *
     * @param requestId
     * @param deferredResult
     */
    public void process(String requestId, DeferredResult<DeferredResultResponse> deferredResult) {
        //          
        deferredResult.onTimeout(() -> {
            taskMap.remove(requestId);
            DeferredResultResponse deferredResultResponse = new DeferredResultResponse();
            deferredResultResponse.setCode(HttpStatus.REQUEST_TIMEOUT.value());
            deferredResultResponse.setMsg(DeferredResultResponse.Msg.TIMEOUT.getDesc());
            deferredResult.setResult(deferredResultResponse);
        });
 
        Optional.ofNullable(taskMap)
                .filter(t -> !t.containsKey(requestId))
                .orElseThrow(() -> new IllegalArgumentException(String.format("requestId=%s is existing", requestId)));
 
        taskMap.putIfAbsent(requestId, deferredResult::setResult);
    }
 
    /**
     *             
     *   DeferredResult   setResult  
     *
     * @param requestId
     * @param deferredResultResponse
     */
    public void settingResult(String requestId, DeferredResultResponse deferredResultResponse) {
        if (taskMap.containsKey(requestId)) {
            Consumer<DeferredResultResponse> deferredResultResponseConsumer = taskMap.get(requestId);
            //      DeferredResult   setResult  
            deferredResultResponseConsumer.accept(deferredResultResponse);
            taskMap.remove(requestId);
        }
    }
 
}
글 마지막 으로 저 는 다른 문 제 를 설명 하고 싶 습 니 다.우 리 는 Deferred Result 를 이용 하여 http 폴 링 을 실 현 했 습 니 다.사실은 생각 을 바 꾸 어 문 제 를 생각 합 니 다.우 리 는 http 인터페이스 지연 을 실현 하지 않 았 습 니까?따라서 시간 을 끌 고 돌아 갈 필요 가 있다 면 Deferred Result 를 통 해 이 루어 질 수 있 습 니 다.
이상 은 자바 가 Deferred Result 를 이용 하여 http 폴 링 을 실현 하여 실시 간 으로 데이터 인터페이스 로 돌아 가 는 상세 한 내용 입 니 다.자바 가 http 폴 링 을 실현 하여 실시 간 으로 데이터 인터페이스 로 돌아 가 는 자 료 는 우리 의 다른 관련 글 을 주목 하 십시오!

좋은 웹페이지 즐겨찾기