下面列出了org.springframework.boot.web.server.WebServer#com.linecorp.armeria.server.ServerBuilder 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private void configureThriftService(ServerBuilder sb, ProjectManager pm, CommandExecutor executor,
WatchService watchService, MetadataService mds) {
final CentralDogmaServiceImpl service =
new CentralDogmaServiceImpl(pm, executor, watchService, mds);
HttpService thriftService =
ThriftCallService.of(service)
.decorate(CentralDogmaTimeoutScheduler::new)
.decorate(CentralDogmaExceptionTranslator::new)
.decorate(THttpService.newDecorator());
if (cfg.isCsrfTokenRequiredForThrift()) {
thriftService = thriftService.decorate(AuthService.newDecorator(new CsrfTokenAuthorizer()));
} else {
thriftService = thriftService.decorate(TokenlessClientLogger::new);
}
// Enable content compression for API responses.
thriftService = thriftService.decorate(contentEncodingDecorator());
sb.service("/cd/thrift/v1", thriftService);
}
private void configureMetrics(ServerBuilder sb, PrometheusMeterRegistry registry) {
sb.meterRegistry(registry);
sb.service(METRICS_PATH, new PrometheusExpositionService(registry.getPrometheusRegistry()));
sb.decorator(MetricCollectingService.newDecorator(MeterIdPrefixFunction.ofDefault("api")));
// Bind system metrics.
new FileDescriptorMetrics().bindTo(registry);
new ProcessorMetrics().bindTo(registry);
new ClassLoaderMetrics().bindTo(registry);
new UptimeMetrics().bindTo(registry);
new DiskSpaceMetrics(cfg.dataDir()).bindTo(registry);
new JvmGcMetrics().bindTo(registry);
new JvmMemoryMetrics().bindTo(registry);
new JvmThreadMetrics().bindTo(registry);
// Bind global thread pool metrics.
ExecutorServiceMetrics.monitor(registry, ForkJoinPool.commonPool(), "commonPool");
}
@Override
public void start() throws Exception {
logger.trace("Getting Armeria Server Builder");
final ServerBuilder sb = ((ArmeriaServerFactory) serverFactory).getServerBuilder();
logger.trace("Calling Server Configurator");
serverConfigurator.configure(sb);
server = sb.build();
if (logger.isDebugEnabled()) {
logger.debug("Built server {}", server);
}
logger.info("Starting Armeria Server");
try {
server.start().join();
} catch (Throwable cause) {
Exceptions.throwUnsafely(Exceptions.peel(cause));
}
logger.info("Started Armeria Server");
}
private static void configureSecureDecorator(ServerBuilder sb, Port port,
@Nullable String basePath, ArmeriaSettings armeriaSettings) {
final DecoratingServiceBindingBuilder builder = sb.routeDecorator();
if (armeriaSettings.isEnableMetrics() && !Strings.isNullOrEmpty(armeriaSettings.getMetricsPath())) {
builder.path(armeriaSettings.getMetricsPath());
}
if (!Strings.isNullOrEmpty(armeriaSettings.getHealthCheckPath())) {
builder.path(armeriaSettings.getHealthCheckPath());
}
if (!Strings.isNullOrEmpty(armeriaSettings.getDocsPath())) {
builder.path(armeriaSettings.getDocsPath());
}
if (!Strings.isNullOrEmpty(basePath)) {
builder.path(basePath)
.pathPrefix(basePath);
}
builder.build((delegate, ctx, req) -> {
final InetSocketAddress laddr = ctx.localAddress();
if (port.getPort() == laddr.getPort()) {
return delegate.serve(ctx, req);
} else {
return HttpResponse.of(404);
}
});
}
@Override
protected void configure(ServerBuilder sb) throws Exception {
sb.service("/http-always", SERVICE.decorate(ThrottlingService.newDecorator(always())));
sb.service("/http-never", SERVICE.decorate(ThrottlingService.newDecorator(never())));
sb.service("/http-never-custom", SERVICE.decorate(
ThrottlingService.newDecorator(ThrottlingStrategy.of((ctx, req) -> completedFuture(false)),
(delegate, ctx, req, cause) -> HttpResponse.of(HttpStatus.SERVICE_UNAVAILABLE))
));
sb.service("/http-always-custom", SERVICE.decorate(
ThrottlingService.builder(ThrottlingStrategy.of((ctx, req) -> completedFuture(true)))
.onAcceptedRequest((delegate, ctx, req) -> {
ctx.addAdditionalResponseHeader(
"X-RateLimit-Limit",
"10, 10;window=1;burst=1000, 1000;window=3600");
return delegate.serve(ctx, req);
})
.newDecorator()
));
}
@Override
protected void configure(ServerBuilder sb) throws Exception {
sb.service("/sse/publisher", (ctx, req) -> ServerSentEvents.fromPublisher(
Flux.just(ServerSentEvent.ofData("foo"), ServerSentEvent.ofData("bar"))));
sb.service("/sse/stream", (ctx, req) -> ServerSentEvents.fromStream(
Stream.of(ServerSentEvent.ofData("foo"), ServerSentEvent.ofData("bar")),
MoreExecutors.directExecutor()));
sb.service("/converter/publisher", (ctx, req) -> ServerSentEvents.fromPublisher(
Flux.just("foo", "bar"), ServerSentEvent::ofComment));
sb.service("/converter/stream", (ctx, req) -> ServerSentEvents.fromStream(
Stream.of("foo", "bar"), MoreExecutors.directExecutor(), ServerSentEvent::ofComment));
sb.service("/single/sse", (ctx, req) -> ServerSentEvents.fromEvent(
ServerSentEvent.ofEvent("add")));
}
@Override
public void initialize(Bootstrap<DropwizardArmeriaConfiguration> bootstrap) {
final ArmeriaBundle<DropwizardArmeriaConfiguration> bundle =
new ArmeriaBundle<DropwizardArmeriaConfiguration>() {
@Override
public void configure(ServerBuilder builder) {
builder.service("/", (ctx, res) -> HttpResponse.of(MediaType.HTML_UTF_8, "<h2>It works!</h2>"));
builder.service("/armeria", (ctx, res) -> HttpResponse.of("Hello, Armeria!"));
builder.annotatedService(new HelloService());
// You can also bind asynchronous RPC services such as Thrift and gRPC:
// builder.service(THttpService.of(...));
// builder.service(GrpcService.builder()...build());
}
};
bootstrap.addBundle(bundle);
}
@Setup
public void startServer() throws Exception {
final ServerBuilder sb =
Server.builder()
.service("/a", THttpService.of((AsyncIface) (name, cb) -> cb.onComplete(RESPONSE))
.decorate(PooledDecoratingService::new))
.service("/b", THttpService.of((AsyncIface) (name, cb) -> cb.onComplete(RESPONSE))
.decorate(UnpooledDecoratingService::new));
server = sb.build();
server.start().join();
final int httpPort = server.activeLocalPort(SessionProtocol.HTTP);
pooledClient = Clients.newClient("tbinary+http://127.0.0.1:" + httpPort + "/a",
HelloService.Iface.class);
unpooledClient = Clients.newClient("tbinary+http://127.0.0.1:" + httpPort + "/b",
HelloService.Iface.class);
}
@Override
protected void configure(ServerBuilder sb) throws Exception {
sb.service("/seq/publisher",
(ctx, req) -> JsonTextSequences.fromPublisher(Flux.just("foo", "bar", "baz", "qux")))
.service("/seq/stream",
(ctx, req) -> JsonTextSequences.fromStream(
Stream.of("foo", "bar", "baz", "qux"), MoreExecutors.directExecutor()))
.service("/seq/custom-mapper",
(ctx, req) -> JsonTextSequences.fromPublisher(
Flux.just("foo", "bar", "baz", "qux"),
new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT)))
.service("/seq/single",
(ctx, req) -> JsonTextSequences.fromObject("foo"));
sb.disableServerHeader();
sb.disableDateHeader();
}
@Override
protected void configure(ServerBuilder sb) throws Exception {
sb.service(
"/",
THttpService.builder()
.addService((Iface) name -> "none:" + name)
.addService("foo", (Iface) name -> "foo:" + name)
.addService("bar", (Iface) name -> "bar:" + name)
.build()
.decorate((delegate, ctx, req) -> {
ctx.log().whenAvailable(RequestLogProperty.REQUEST_CONTENT)
.thenAccept(log -> {
final RpcRequest call = (RpcRequest) log.requestContent();
if (call != null) {
methodNames.add(call.method());
}
});
return delegate.serve(ctx, req);
}));
}
@Override protected void configure(ServerBuilder sb) {
sb.serviceUnder("/", (ctx, req) -> HttpResponse.from(
req.aggregate().thenApply(agg -> {
CAPTURED_REQUEST.set(agg);
return MOCK_RESPONSE.get().toHttpResponse();
})));
}
@Override protected void configure(ServerBuilder sb) {
sb.serviceUnder("/", (ctx, req) -> HttpResponse.from(
req.aggregate().thenApply(agg -> {
CAPTURED_REQUEST.set(agg);
return MOCK_RESPONSE.get().toHttpResponse();
})));
}
@Override
protected void configure(ServerBuilder sb) throws Exception {
sb.service(HEALTH_CHECK_PATH, HealthCheckService.builder()
.longPolling(LONG_POLLING_TIMEOUT)
.checkers(health)
.build());
// Enable graceful shutdown so that the server is given a chance
// to send a health check response when the server is shutting down.
// Without graceful shutdown, the health check request will be aborted
// with GOAWAY or disconnection.
sb.gracefulShutdownTimeoutMillis(3000, 10000);
}
@Override
protected void configure(ServerBuilder sb) throws Exception {
final TokenBucket tokenBucket = TokenBucket.builder()
.limit(1L, Duration.ofSeconds(10L))
.build();
sb.service("/http-serve",
SERVICE.decorate(
ThrottlingService.newDecorator(
TokenBucketThrottlingStrategy.<HttpRequest>builder(tokenBucket)
.build())));
sb.service("/http-throttle1",
SERVICE.decorate(
ThrottlingService.newDecorator(
TokenBucketThrottlingStrategy.<HttpRequest>builder(tokenBucket)
.withHeadersScheme(ThrottlingHeaders.X_RATELIMIT)
.build())));
sb.service("/http-throttle2",
SERVICE.decorate(
ThrottlingService.newDecorator(
TokenBucketThrottlingStrategy.<HttpRequest>builder(tokenBucket)
.withMinimumBackoff(Duration.ofSeconds(15L))
.withHeadersScheme(ThrottlingHeaders.X_RATELIMIT, true)
.build())));
sb.service("/http-throttle3",
SERVICE.decorate(
ThrottlingService.newDecorator(
TokenBucketThrottlingStrategy.<HttpRequest>builder(tokenBucket)
.build())));
sb.service("/http-throttle4",
SERVICE.decorate(
ThrottlingService.newDecorator(
TokenBucketThrottlingStrategy.<HttpRequest>builder(tokenBucket)
.withMinimumBackoff(Duration.ofSeconds(5L))
.build(),
(delegate, ctx, req, cause) ->
HttpResponse.of(HttpStatus.SERVICE_UNAVAILABLE))));
}
@Override
protected void configure(ServerBuilder sb) throws Exception {
sb.annotatedService("/1", new MyDecorationService1());
sb.annotatedService("/2", new MyDecorationService2());
sb.annotatedService("/3", new MyDecorationService3());
sb.annotatedService("/4", new MyDecorationService4());
}
private static void configureCompression(ServerBuilder serverBuilder, Compression compression) {
if (compression.isEnabled()) {
final int minBytesToForceChunkedAndEncoding;
final String minResponseSize = compression.getMinResponseSize();
if (minResponseSize == null) {
minBytesToForceChunkedAndEncoding = DEFAULT_MIN_BYTES_TO_FORCE_CHUNKED_AND_ENCODING;
} else {
minBytesToForceChunkedAndEncoding = Ints.saturatedCast(parseDataSize(minResponseSize));
}
serverBuilder.decorator(contentEncodingDecorator(compression.getMimeTypes(),
compression.getExcludedUserAgents(),
minBytesToForceChunkedAndEncoding));
}
}
private static void configureHttp1(ServerBuilder serverBuilder, Http1 http1) {
if (http1.getMaxInitialLineLength() != null) {
serverBuilder.http1MaxInitialLineLength(http1.getMaxInitialLineLength());
}
if (http1.getMaxChunkSize() != null) {
serverBuilder.http1MaxChunkSize((int) parseDataSize(http1.getMaxChunkSize()));
}
}
@Override
protected void configure(ServerBuilder sb) throws Exception {
sb.service("/ping", HealthCheckService.builder()
.longPolling(Duration.ofSeconds(60), 0,
Duration.ofSeconds(1))
.build());
sb.service("/no_ping_after_initial_ping", (ctx, req) -> {
// Send a healthy response for non-long-polling request
// so that the client sends a long-polling request next time.
if (!req.headers().contains(HttpHeaderNames.IF_NONE_MATCH)) {
return HttpResponse.of(ResponseHeaders.of(HttpStatus.OK,
"armeria-lphc", "60, 1"));
}
// Do not send anything but the initial ping.
final HttpResponseWriter res = HttpResponse.streaming();
res.write(ResponseHeaders.of(HttpStatus.PROCESSING,
"armeria-lphc", "60, 1"));
return res;
});
sb.service("/no_ping_at_all", (ctx, req) -> {
// Send a healthy response for non-long-polling request
// so that the client sends a long-polling request next time.
if (!req.headers().contains(HttpHeaderNames.IF_NONE_MATCH)) {
return HttpResponse.of(ResponseHeaders.of(HttpStatus.OK,
"armeria-lphc", "60, 1"));
}
// Do not send anything, even the initial ping.
return HttpResponse.streaming();
});
}
@Override
protected void configure(ServerBuilder sb) throws Exception {
sb.tls(serverCert.certificateFile(), serverCert.privateKeyFile());
sb.tlsCustomizer(sslCtxBuilder -> {
sslCtxBuilder.trustManager(InsecureTrustManagerFactory.INSTANCE)
.clientAuth(ClientAuth.REQUIRE);
});
sb.service("/", (ctx, req) -> HttpResponse.of("success"));
sb.decorator(LoggingService.builder().newDecorator());
}
@Override
protected void configure(ServerBuilder sb) throws Exception {
sb.service("/secret", (ctx, req) -> {
return HttpResponse.from(req.aggregate().thenApply(aggReq -> {
if ("Bearer: access-token".equals(aggReq.headers().get(HttpHeaderNames.AUTHORIZATION))) {
return HttpResponse.of("\"OK\"");
} else {
return HttpResponse.of(HttpStatus.FORBIDDEN);
}
}));
});
sb.service("/slow", (ctx, req) ->
HttpResponse.delayed(HttpResponse.of("\"OK\""), Duration.ofSeconds(2)));
}
private ServerBuilder buildServerBuilder(Server server, MetricRegistry metricRegistry) {
final ServerBuilder serverBuilder = com.linecorp.armeria.server.Server.builder();
serverBuilder.meterRegistry(DropwizardMeterRegistries.newRegistry(metricRegistry));
if (armeriaSettings != null) {
ArmeriaConfigurationUtil.configureServer(serverBuilder, armeriaSettings);
} else {
logger.warn("Armeria configuration was null. ServerBuilder is not customized from it.");
}
return serverBuilder.blockingTaskExecutor(newBlockingTaskExecutor(), true)
.serviceUnder("/", JettyService.of(server));
}
@Override
public void initialize(Bootstrap<TestConfiguration> bootstrap) {
final ArmeriaBundle<TestConfiguration> bundle =
new ArmeriaBundle<TestConfiguration>() {
@Override
public void configure(ServerBuilder builder) {
builder.service("/armeria", (ctx, res) -> HttpResponse.of("Hello, Armeria!"));
}
};
bootstrap.addBundle(bundle);
}
@Test
void configureServer() throws Exception {
final File yml = new File(resourceFilePath("armeria-settings.yaml"));
final ArmeriaSettings armeriaSettings = configFactory.build(yml);
armeriaSettings.setSsl(null);
final ServerBuilder serverBuilder = Server.builder()
.service("/foo", (ctx, req) -> HttpResponse.of(200));
serverBuilder.tlsSelfSigned();
ArmeriaConfigurationUtil.configureServer(serverBuilder, armeriaSettings);
final Server server = serverBuilder.build();
assertThat(server.defaultHostname()).isEqualTo("host.name.com");
assertThat(server.config().maxNumConnections()).isEqualTo(5000);
assertThat(server.config().isDateHeaderEnabled()).isFalse();
assertThat(server.config().isServerHeaderEnabled()).isTrue();
assertThat(server.config().defaultVirtualHost().maxRequestLength()).isEqualTo(10485761);
assertThat(server.config().ports()).hasSize(3);
assertThat(server.config().ports()).containsExactly(
new ServerPort(8080, SessionProtocol.HTTP),
new ServerPort(new InetSocketAddress("127.0.0.1", 8081), SessionProtocol.HTTPS),
new ServerPort(8443, SessionProtocol.HTTPS, SessionProtocol.PROXY)
);
assertThat(server.config().http1MaxChunkSize()).isEqualTo(4000);
assertThat(server.config().http1MaxInitialLineLength()).isEqualTo(4096);
assertThat(server.config().http1MaxInitialLineLength()).isEqualTo(4096);
assertThat(server.config().http2InitialConnectionWindowSize()).isEqualTo(1024 * 1024 * 2);
assertThat(server.config().http2InitialStreamWindowSize()).isEqualTo(1024 * 1024 * 2);
assertThat(server.config().http2MaxFrameSize()).isEqualTo(16385);
assertThat(server.config().http2MaxHeaderListSize()).isEqualTo(8193);
assertThat(server.config().proxyProtocolMaxTlvSize()).isEqualTo(65320);
}
static boolean addExposition(ArmeriaSettings settings, ServerBuilder server,
MeterRegistry meterRegistry) {
final String metricsPath = settings.getMetricsPath();
assert metricsPath != null;
for (;;) {
if (meterRegistry instanceof PrometheusMeterRegistry) {
final CollectorRegistry prometheusRegistry =
((PrometheusMeterRegistry) meterRegistry).getPrometheusRegistry();
server.service(metricsPath, new PrometheusExpositionService(prometheusRegistry));
return true;
}
if (meterRegistry instanceof CompositeMeterRegistry) {
final Set<MeterRegistry> childRegistries =
((CompositeMeterRegistry) meterRegistry).getRegistries();
final Optional<PrometheusMeterRegistry> opt =
childRegistries.stream()
.filter(PrometheusMeterRegistry.class::isInstance)
.map(PrometheusMeterRegistry.class::cast)
.findAny();
if (!opt.isPresent()) {
return false;
}
meterRegistry = opt.get();
continue;
}
return false;
}
}
@Override
protected void configure(ServerBuilder sb) throws Exception {
sb.service("/", (ctx, req) -> HttpResponse.from(
req.aggregate()
.thenApply(aggregated -> {
final ResponseHeaders responseHeaders =
ResponseHeaders.of(HttpStatus.OK,
HttpHeaderNames.CONTENT_TYPE, MediaType.PLAIN_TEXT_UTF_8);
return HttpResponse.of(responseHeaders,
HttpData.ofUtf8("Hello " + aggregated.contentUtf8() + '!'));
})));
sb.decorator(EncodingService.builder()
.minBytesToForceChunkedEncoding(1)
.newDecorator());
}
@Override
protected void configure(ServerBuilder sb) throws Exception {
sb.service("/no_value",
(ctx, req) -> HttpResponse.of(HttpStatus.OK));
sb.service("/bad_value",
(ctx, req) -> HttpResponse.of(ResponseHeaders.of(
HttpStatus.OK, "armeria-lphc", "bad_value")));
sb.service("/0.97",
(ctx, req) -> HttpResponse.of(ResponseHeaders.of(
HttpStatus.OK, "armeria-lphc", 60)));
}
@Test
void makesSureDecoratorsAreConfigured() {
final Function<? super HttpService, ? extends HttpService> decorator = spy(new IdentityFunction());
final AnnotatedServiceRegistrationBean bean = new AnnotatedServiceRegistrationBean()
.setServiceName("test")
.setService(new SimpleService())
.setDecorators(decorator);
final ServerBuilder sb1 = Server.builder();
final DocServiceBuilder dsb1 = DocService.builder();
configureAnnotatedServices(sb1, dsb1, ImmutableList.of(bean),
MeterIdPrefixFunctionFactory.ofDefault(), null);
final Server s1 = sb1.build();
verify(decorator, times(2)).apply(any());
assertThat(service(s1).as(MetricCollectingService.class)).isNotNull();
reset(decorator);
final ServerBuilder sb2 = Server.builder();
final DocServiceBuilder dsb2 = DocService.builder();
configureAnnotatedServices(sb2, dsb2, ImmutableList.of(bean),
null, null);
final Server s2 = sb2.build();
verify(decorator, times(2)).apply(any());
assertThat(getServiceForHttpMethod(sb2.build(), HttpMethod.OPTIONS))
.isInstanceOf(AnnotatedService.class);
}
@Test
void makesSureDecoratedServiceIsAdded() {
final Function<? super HttpService, ? extends HttpService> decorator = spy(new DecoratingFunction());
final AnnotatedServiceRegistrationBean bean = new AnnotatedServiceRegistrationBean()
.setServiceName("test")
.setService(new SimpleService())
.setDecorators(decorator);
final ServerBuilder sb = Server.builder();
final DocServiceBuilder dsb = DocService.builder();
configureAnnotatedServices(sb, dsb, ImmutableList.of(bean), null, null);
final Server s = sb.build();
verify(decorator, times(2)).apply(any());
assertThat(service(s).as(SimpleDecorator.class)).isNotNull();
}
@Override
protected void configure(ServerBuilder sb) throws Exception {
sb.meterRegistry(PrometheusMeterRegistries.newRegistry());
sb.serviceUnder("/qux/", composite);
// Should not hit the following services
sb.serviceUnder("/foo/", otherService);
sb.serviceUnder("/bar/", otherService);
sb.service(Route.builder().glob("/*").build(), otherService);
}
@PostConstruct
public void init() {
ServerBuilder sb = new ServerBuilder().http(8085)
.service("/healthCheck", (ctx, res) -> HttpResponse.of(SUCCESS))
.service("/greet/{name}", (ctx, res) -> HttpResponse.of("Hello %s~", ctx.pathParam("name")));
Server server = sb.build();
CompletableFuture<Void> future = server.start();
future.join();
}