我已经使用Dropwizard创建了一个启动gRPC服务器的应用程序。我不使用常规服务器,而是想使用java -jar my-fat.jar grpc config.yml
启动我的应用程序。
我已经通过覆盖应用程序类中的相应方法来将命令添加为启动期间唯一可用的命令:
public class App extends Application<Configuration> {
public static void main(String[] args) throws Exception {
new App().run(args);
}
@Override
protected void addDefaultCommands(final Bootstrap<Configuration> bootstrap) {
bootstrap.addCommand(new GrpcCommand(this));
}
}
我可以使用java -jar my-fat.jar grpc config.yml
启动我的应用程序。我的命令如下所示:
public class GrpcCommand extends EnvironmentCommand<Configuration> {
public GrpcCommand(Application<Configuration> application) {
this(application, "grpc", "Runs the Dropwizard application as a gRPC server");
}
/**
* Creates a new environment command.
*
* @param application the application providing this command
* @param name the name of the command, used for command line invocation
* @param description a description of the command's purpose
*/
protected GrpcCommand(final Application<Configuration> application, final String name, final String description) {
super(application, name, description);
}
@Override
protected void run(final Environment environment, final Namespace namespace, final Configuration configuration) throws Exception {
final var certificateService = AzureCertificateService.createWithClients(
AzureSecretClient.create(configuration.getKeyVaultConfiguration()),
AzureCertificateClient.create(configuration.getKeyVaultConfiguration())
);
final var validationService = CertificateValidationService.create(certificateService);
final var signingService = CertificateSigningService.create(certificateService);
final Pair<X509Certificate, KeyPair> certificate = certificateService.getSigningCertificateWithKeyPair();
final BaseApiImpl baseApi = new BaseApiImpl(validationService, signingService);
final GrpcServer grpcServer = GrpcServer.newBuilder()
.withBaseApi(baseApi)
.withConfiguration(configuration.getGrpcConfiguration())
.withCertificate(certificate.getLeft())
.withPrivateKey(certificate.getRight().getPrivate())
.build();
new Thread(() -> {
try {
grpcServer.start();
} catch (Exception e) {
e.printStackTrace();
}
}).run();
environment.healthChecks().register("grpc-server", new GrpcServerHealthCheck(grpcServer));
}
}
线程启动的方式不适用于生产,我只是想前进。 GrpcServer
类的启动方法:
@Override
public void start() throws Exception {
final NettyServerBuilder nettyServerBuilder = NettyServerBuilder.forPort(configuration.getPort())
.addService(baseApi)
.intercept(new OriginInterceptor());
if (certificate != null && privateKey != null) {
LOG.info("Got certificate and private key, enabling SSL");
nettyServerBuilder.sslContext(buildSslContext());
}
server = nettyServerBuilder
.build()
.start();
LOG.info("Server started at port {}", server.getPort());
}
并且当我启动时,我在日志中看到消息GrpcServer: Server started at port 50441
。但是,该应用程序不会保持打开状态。我想念什么?我不应该使用该线程创建一个阻止应用程序退出的线程吗? gRPC服务器启动后,如何保持应用程序运行?
当我禁用服务器命令时,(当然)Jetty也未启动,这使该应用程序以前一直处于活动状态。
我在gRPC Hello World Example中找到了最简单的解决方案。
我的启动方法现在看起来像这样:
public void start() throws Exception {
// Everything else as above
Runtime.getRuntime().addShutdownHook(new Thread(GrpcServer.this::stop));
LOG.info("Server started at port {}", server.getPort());
blockUntilShutdown();
}
private void blockUntilShutdown() throws InterruptedException {
if (server != null) {
server.awaitTermination();
}
}