span span = handler.handlereceive(extractor, httprequest);
// add attributes for explicit access to customization or span context
request.setattribute(spancustomizer.class.getname(), span.customizer());
request.setattribute(tracecontext.class.getname(), span.context());
throwable error = null;
scope scope = currenttracecontext.newscope(span.context());
try {
// any downstream code can see tracer.currentspan() or use tracer.currentspancustomizer()
chain.dofilter(httprequest, httpresponse);
} catch (ioexception | servletexception | runtimeexception | error e) {
error = e;
throw e;
} finally {
scope.close();
if (servlet.isasync(httprequest)) { // we don't have the actual response, handle later
servlet.handleasync(handler, httprequest, httpresponse, span);
} else { // we have a synchronous response, so we can finish the span
handler.handlesend(adapter.adaptresponse(httprequest, httpresponse), error, span);
}
}
}
public static final class default extends currenttracecontext {
static final threadlocal<tracecontext> default = new threadlocal<>();
// inheritable as brave 3's threadlocalserverclientandlocalspanstate was inheritable
static final inheritablethreadlocal<tracecontext> inheritable = new inheritablethreadlocal<>();
final threadlocal<tracecontext> local;
//静态方法create,local对象为threadlocal类型
/** uses a non-inheritable static thread local */
public static currenttracecontext create() {
return new default(default);
}
//local对象为inheritablethreadlocal类型
//官方文档指出,inheritable方法在线程池的环境中需谨慎使用,可能会取出错误的tracecontext,这样会导致span等信息会记录并关联到错误的traceid上
/**
* uses an inheritable static thread local which allows arbitrary calls to {@link
* thread#start()} to automatically inherit this context. this feature is available as it is was
* the default in brave 3, because some users couldn't control threads in their applications.
*
* <p>this can be a problem in scenarios such as thread pool expansion, leading to data being
* recorded in the wrong span, or spans with the wrong parent. if you are impacted by this,
* switch to {@link #create()}.
*/
public static currenttracecontext inheritable() {
return new default(inheritable);
}
default(threadlocal<tracecontext> local) {
if (local == null) throw new nullpointerexception("local == null");
this.local = local;
}
@override public tracecontext get() {
return local.get();
}
//替换当前tracecontext,close方法将之前的tracecontext设置回去
//scope接口继承了closeable接口,在try中使用会自动调用close方法,为了避免用户忘记close方法,还提供了runnable,callable,executor,executorservice包装方法
@override public scope newscope(@nullable tracecontext currentspan) {
final tracecontext previous = local.get();
local.set(currentspan);
class defaultcurrenttracecontextscope implements scope {
@override public void close() {
local.set(previous);
}
}
return new defaultcurrenttracecontextscope();
}
}