HttpClient 판독 (3) - http 연결 의 반환, 닫 기

10541 단어 반환 연결release
더 읽 기
이전 편 에 서 는 주로 빌려 준 후에 어떻게 사용 하 는 지 에 대해 설명 하 였 으 며, 이 편 에 서 는 어떻게 반환 하 는 지, 다시 사용 하 는 부분의 코드 로 돌아 가 는 지, MinimalClient Exec. execute (HttpRoute, HttpRequest Wrapper, HttpClient Context, HttpExecution Aware) 의 맨 뒤의 몇 줄 을 소개 하 였 다.
final ConnectionHolder releaseTrigger = new ConnectionHolder(log, connManager, managedConn);//           connection,    
。。。        
if (reuseStrategy.keepAlive(response, context)) {//   keepalive      
	// Set the idle duration of this connection
	final long duration = keepAliveStrategy.getKeepAliveDuration(response, context);
	releaseTrigger.setValidFor(duration, TimeUnit.MILLISECONDS);//          
	releaseTrigger.markReusable();//          
} else {
	releaseTrigger.markNonReusable();//    1.1 keepalive,         。
}

// check for entity, release connection if possible
final HttpEntity entity = response.getEntity();
if (entity == null || !entity.isStreaming()) {//      stream ,    tomcat     stream ,            
	releaseTrigger.releaseConnection();
	return new HttpResponseProxy(response, null);
} else {
	return new HttpResponseProxy(response, releaseTrigger);//       response       ,         response releaseTrigger,       httpconnection
}

 http Response Proxy 코드 좀 봅 시다.
private final HttpResponse original;//      httpResponse,
private final ConnectionHolder connHolder;//    httpConnection,      httpConnection。

public HttpResponseProxy(final HttpResponse original, final ConnectionHolder connHolder) {
	this.original = original;
	this.connHolder = connHolder;
	ResponseEntityProxy.enchance(original, connHolder);//       HTTPResponse    ,       
}

 위의 Http Response Proxy 는 하나의 에이전트 일 뿐 입 니 다. 저 희 는 reponse 를 사용 할 때 getEntity 방법 을 사 용 했 습 니 다. getStatusLine 방법 을 사 용 했 습 니 다. 그 는 모두 호출 된 안에 포 장 된 original 방법 이지 만 getEntity. getContent 를 호출 할 때 구체 적 인 내용 을 얻 었 을 때 는 그렇지 않 습 니 다.위의 구조 방법 에서 original 이 되 돌아 오 는 Entity 대상 을 강 화 했 기 때문에 ResponseEntity Proxy. enchance (HttpResponse, Connection Holder) 를 보십시오.
 
 
public static void enchance(final HttpResponse response, final ConnectionHolder connHolder) {
	final HttpEntity entity = response.getEntity();//   reponse     original,         
        if (entity != null && entity.isStreaming() && connHolder != null) {
		response.setEntity(new ResponseEntityProxy(entity, connHolder));//           entity,     ResponseEntityProxy,     Entity,      getContent  
	}
}
@Override
public InputStream getContent() throws IOException {
	return new EofSensorInputStream(this.wrappedEntity.getContent(), this);//        ,       inputStream,           ,     EofSensorInputStream
}

 그의 자바 주석 에는 close 에서 동작 을 촉발 하 는 데 사 용 됩 니 다. 주로 바 텀 연결 을 방출 하 는 데 사 용 됩 니 다. 그의 구조 방법 에는 EofSensor Watcher, 즉 모니터 모드 의 응용 이 있 습 니 다. eof (end of file) 에 서 는 모니터 를 호출 합 니 다.
이렇게 response. getEntity. getContent 를 호출 할 때 EofSensor InputStream 을 되 돌려 줍 니 다. 그의 read 방법 을 보 세 요.
@Override
public int read() throws IOException {
	int l = -1;
	if (isReadAllowed()) {
		try {
			l = wrappedStream.read();
			checkEOF(l);
		} catch (final IOException ex) {
			checkAbort();
			throw ex;
		}
	}
	return l;
}
@Override
public int read(final byte[] b, final int off, final int len) throws IOException {
	int l = -1;
	if (isReadAllowed()) {
		try {
			l = wrappedStream.read(b,  off,  len);
			checkEOF(l);
		} catch (final IOException ex) {
			checkAbort();throw ex;
		}
	}
	return l;
}
@Override
public int read(final byte[] b) throws IOException {
	return read(b, 0, b.length);
}

 그의 read 작업 은 모두 호출 된 봉 인 된 input Stream 의 방법 임 을 발견 할 수 있 습 니 다. 어떠한 강화 도 없 으 니 그의 close 방법 을 보십시오.
public void close() throws IOException {
	selfClosed = true;//          ,
	checkClose();//     ,        
}
protected void checkClose() throws IOException {
	if (wrappedStream != null) {
		try {
			boolean scws = true; // should close wrapped stream?
			if (eofWatcher != null) {
				scws = eofWatcher.streamClosed(wrappedStream);//      
			}
			if (scws) {
				wrappedStream.close();
			}
		} finally {
			wrappedStream = null;
		}
	}
}

 이전에 입 은 모니터 가 ResponseEntity Proxy 였 습 니 다. 그의 streamClosed 방법 을 보 세 요.
public boolean streamClosed(final InputStream wrapped) throws IOException {
	try {
		final boolean open = connHolder != null && !connHolder.isReleased();//       httpConnection   ,    
		try {
			wrapped.close();
			releaseConnection();//                   releaseConnection  ,
		} catch (final SocketException ex) {
			if (open) {throw ex;}
		}
	} finally {cleanup();}
	return false;
}
public void releaseConnection() throws IOException {
	if (this.connHolder != null) {
		try {
			if (this.connHolder.isReusable()) {//     ,   release  ,               keepalive   ,        ,
				this.connHolder.releaseConnection();//       :
			}
		} finally {
			cleanup();
		}
	}
}

ConnectionHolder.releaseConnection():
public void releaseConnection() {
	synchronized (this.managedConn) {
		if (this.released) {
			return;
		}
		this.released = true;
		if (this.reusable) {//   1.1      
			this.manager.releaseConnection(this.managedConn,this.state, this.validDuration, this.tunit);//manager       PoolingHttpClientConnectionManager,          connection,          
		} else {//    ,     http     
			try {
				this.managedConn.close();
			} catch (final IOException ex) {
				if (this.log.isDebugEnabled()) {
					this.log.debug(ex.getMessage(), ex);
				}
			} finally {
				this.manager.releaseConnection(this.managedConn, null, 0, TimeUnit.MILLISECONDS);
			}
		}
	}
}

 위 에 여러 층 의 대 리 를 거 쳤 습 니 다. 처음에 Http Response Proxy 는 맨 밑 에 있 는 http Response 를 대 리 했 습 니 다. 대 리 를 할 때 맨 밑 에 있 는 HTTP Response 의 enity 를 강 화 했 습 니 다. 강 화 된 enity 의 getContent 방법 은 작업 을 감사 하고 닫 을 수 있 는 inpustream 으로 되 돌아 갑 니 다. 닫 을 때 connection Holder 의 연결 해제 작업 을 호출 합 니 다.연결 을 풀 면 캐 시 풀 에 넣 고 검사 시간 도 업데이트 합 니 다.그래서 지금 은 가장 바깥쪽 에 있 는 inpustream 을 닫 으 면 자동 으로 연결 을 풀 어 캐 시 풀 에 넣 습 니 다.그리고 PoolingHttpClient ConnectionManager 의 연결 해제 방법 은 보지 않 았 습 니 다.
public void releaseConnection(final HttpClientConnection managedConn,final Object state,final long keepalive, final TimeUnit tunit) {//          connection,       keepalive  ,        
	synchronized (managedConn) {
		final CPoolEntry entry = CPoolProxy.detach(managedConn);//       CPoolEntry,           CPoolProxy   ,       。
		if (entry == null) {
			return;
		}
		final ManagedHttpClientConnection conn = entry.getConnection();//   connection
		try {
			if (conn.isOpen()) {
				final TimeUnit effectiveUnit = tunit != null ? tunit : TimeUnit.MILLISECONDS;
				entry.setState(state);
				entry.updateExpiry(keepalive, effectiveUnit);//      
			}
		} finally {
			this.pool.release(entry, conn.isOpen() && entry.isRouteComplete());//    CPool release  ,        。
		}
	}
}

 CPool 의 연결 해제 방법:
@Override
public void release(final E entry, final boolean reusable) {
	this.lock.lock();
	try {
		if (this.leased.remove(entry)) {//         
			final RouteSpecificPool pool = getPool(entry.getRoute());//       
			pool.free(entry, reusable);//    
			if (reusable && !this.isShutDown) {//    ,             
				this.available.addFirst(entry);
				onRelease(entry);//    ,      
			} else {
				entry.close();
			}
			PoolEntryFuture future = pool.nextPending();//            ,      ,         。
			if (future != null) {
				this.pending.remove(future);
			} else {
				future = this.pending.poll();
			}
			if (future != null) {
				future.wakeup();
			}
		}
	} finally {
		this.lock.unlock();
	}
}

이렇게 하면 전체 반환 절차 가 끝난다.http Client 를 사용 할 때 마지막 input Stream 의 close 방법 을 호출 하면 빌려 준 연결 이 자동 으로 캐 시 풀 로 돌아 오 는 것 을 발견 할 수 있 습 니 다. 즉, Entity Utils. consume (entiry) 을 사용 하면 됩 니 다.
 
 
위 에서 반환 을 보고 또 다른 문 제 를 일 으 켰 습 니 다. 즉, 우리 가 inpustream 을 닫 았 음 에 도 불구 하고 사실 socket 밑바닥 은 닫 히 지 않 았 습 니 다. socket 이 함 유 된 connection 을 연결 풀 로 바 꾸 었 을 뿐 입 니 다. 그리고 만 료 된 연결 도 연결 풀 안에 있 습 니 다. socket 을 어떻게 끄 고 만 료 된 socket 을 끄 는 방법 입 니까?
프로그램 을 닫 을 때 모든 연결 을 닫 는 수요 에 대해 서 는 http Client 전 체 를 spring 의 bean 으로 사용 한 다음 용 기 를 닫 을 때 http Client 를 닫 으 면 캐 시 풀 전체 가 닫 힙 니 다. 프로그램 이 실행 되 는 동안 만 료 된 연결 을 닫 는 수요 에 대해 서 는(만 료 된 연결 은 이 연결 이 가 져 올 때 도 검사 되 지만 검사 되 지 않 은 시간 전에 자원 낭 비 를 초래 할 수 있 습 니 다) 배경 에서 만 료 되 거나 장시간 사용 되 지 않 은 연결 을 자동 으로 검사 할 수 있 도록 설정 을 열 수 있 습 니 다.(만 료 된 연결 은 keepalive 의 시간 을 초과 하고 장시간 사용 하지 않 은 것 은 마지막 업데이트 시간 이 너무 긴 연결 입 니 다) 구체 적 인 작업 은:
HttpClientBuilder hcb = HttpClientBuilder.create();	
hcb.setConnectionManager(poolManager);//  
hcb.setDefaultRequestConfig(httpConfig);//  
hcb.evictExpiredConnections();//         
hcb.evictIdleConnections(maxIdleTime, maxIdleTimeUnit)//         ,               ,       ,          ,      maxIdleTime    ,  AbstractConnPool.closeIdle(long, TimeUnit) closeExpired  。

 
자, http 클 라 이언 트 의 원본 코드 는 여기 있 습 니 다. 우리 응용 층 에 대한 응용 이 충분히 깊 습 니 다. 전체 과정 에서 http 연결 과 직접 관련 된 동작 을 쓰 지 않 았 습 니 다. 예 를 들 어 Connection Factory, Connection Config, HttpRequestExecutor 등 은 http 방면 의 조작 이기 때문에 우리 에 게 투명 하고 사용 에 방해 가 되 지 않 습 니 다. 다만 보 세 요.좋 습 니 다. 예 를 들 어 HttpRequestExecutor 의 HttpRequestExecutor. execute (HttpRequest, HttpClient Connection, HttpContext) 방법 을 보면 http 상태 코드 의 사용 을 볼 수 있 고 100 시 에 socket 요청 을 계속 보 냅 니 다.
블 로그 에 많은 오류 가 있 을 것 입 니 다. 만약 에 네티즌 이 어디 가 틀 렸 는 지 보면 연락 주세요. 제 qq 는 1308567317 입 니 다. 제 가 고 쳐 서 여러분 을 오도 할 수 있 습 니 다.
 
 
 

좋은 웹페이지 즐겨찾기