Connect to Java apps

यह कंटेंट अभी तक आपकी भाषा में उपलब्ध नहीं है।

Java logo

This article describes how the Java apps in your Aspire solution connect to other resources, in both directions. When another resource references a Java app, Aspire injects the Java app’s URL into that resource, so apps written in C#, Go, Python, TypeScript, or Java can call it without hard-coded addresses. When a Java app references other resources — such as a database, a cache, or another service — Aspire injects their URLs and connection details into the JVM as environment variables, which Spring Boot, Quarkus, and plain Java apps read through their standard configuration mechanisms. It also describes how Java apps send telemetry to the Aspire dashboard and trust the development certificate.

For the AppHost APIs that add and configure Java apps, see Set up Java apps in the AppHost. If you’re new to the Java integration, start with Get started with the Java integration.

The examples in this article use the following AppHost. The orders Spring Boot app references a PostgreSQL database and the catalog Spring Boot app, and a Node.js storefront app references orders:

apphost.mts
import {
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
} from './.aspire/modules/aspire.mjs';
const
const builder: IDistributedApplicationBuilder
builder
= await
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
();
const
const postgres: PostgresServerResource
postgres
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addPostgres(name: string, options?: {
userName?: string | ParameterResource;
password?: string | ParameterResource;
port?: number;
}): PostgresServerResource (+1 overload)

Adds a PostgreSQL resource to the application model. A container is used for local development.

addPostgres
('postgres');
const
const ordersDb: PostgresDatabaseResource
ordersDb
= await
const postgres: PostgresServerResource
postgres
.
PostgresServerResource.addDatabase(name: string, options?: {
databaseName?: string;
} | undefined): PostgresDatabaseResource (+1 overload)

Adds a PostgreSQL database to the application model.

addDatabase
('ordersdb');
const
const catalog: JavaAppResource
catalog
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addSpringBootApp(name: string, appDirectory: string): JavaAppResource

Adds a Spring Boot application to the application model, built and launched with its own Maven or Gradle wrapper.

addSpringBootApp
('catalog', '../catalog');
const
const orders: JavaAppResource
orders
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addSpringBootApp(name: string, appDirectory: string): JavaAppResource

Adds a Spring Boot application to the application model, built and launched with its own Maven or Gradle wrapper.

addSpringBootApp
('orders', '../orders');
await
const orders: JavaAppResource
orders
.
ExecutableResource.withReference(source: IResource | EndpointReference | string | uri, options?: {
connectionName?: string;
optional?: boolean;
name?: string;
} | undefined): JavaAppResource (+1 overload)

Adds a reference to another resource

withReference
(
const ordersDb: PostgresDatabaseResource
ordersDb
);
await
const orders: JavaAppResource
orders
.
ExecutableResource.withReference(source: IResource | EndpointReference | string | uri, options?: {
connectionName?: string;
optional?: boolean;
name?: string;
} | undefined): JavaAppResource (+1 overload)

Adds a reference to another resource

withReference
(
const catalog: JavaAppResource
catalog
);
await
const orders: JavaAppResource
orders
.
ExecutableResource.waitFor(dependency: IResource | IResourceWithConnectionString, waitBehavior?: WaitBehavior): JavaAppResource

Waits for another resource to be ready

waitFor
(
const ordersDb: PostgresDatabaseResource
ordersDb
);
await
const orders: JavaAppResource
orders
.
ExecutableResource.waitFor(dependency: IResource | IResourceWithConnectionString, waitBehavior?: WaitBehavior): JavaAppResource

Waits for another resource to be ready

waitFor
(
const catalog: JavaAppResource
catalog
);
const
const storefront: NodeAppResource
storefront
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addNodeApp(name: string, appDirectory: string, scriptPath: string): NodeAppResource

Adds a node application to the application model. Node should be available on the PATH.

addNodeApp
('storefront', '../storefront', 'server.js');
await
const storefront: NodeAppResource
storefront
.
ExecutableResource.withReference(source: IResource | EndpointReference | string | uri, options?: {
connectionName?: string;
optional?: boolean;
name?: string;
} | undefined): NodeAppResource (+1 overload)

Adds a reference to another resource

withReference
(
const orders: JavaAppResource
orders
);
await
const storefront: NodeAppResource
storefront
.
ExecutableResource.waitFor(dependency: IResource | IResourceWithConnectionString, waitBehavior?: WaitBehavior): NodeAppResource

Waits for another resource to be ready

waitFor
(
const orders: JavaAppResource
orders
);
await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.build(): DistributedApplication

Builds the distributed application

build
().
DistributedApplication.run(cancellationToken?: cancellationToken): void

Runs the distributed application

run
();

WithReferencewithReference injects the referenced resource’s connection information into the referencing resource, and WaitForwaitFor delays the referencing resource until the referenced one is running — or healthy, when it has a health check. A Java app can be on either side of a reference, and the environment variables are the same whatever language the other app uses.

Aspire passes connection information to apps as environment variables. A Java app is on both sides of that exchange: it exposes endpoints that other apps call, and it receives variables of its own.

Variables for apps that reference a Java app

Section titled “Variables for apps that reference a Java app”

When a resource references a Java app, Aspire injects the URL of each of the Java app’s endpoints. In the preceding AppHost, storefront receives the following variables for the orders app:

Environment variableDescription
ORDERS_HTTPThe URL of the orders app’s http endpoint, named {RESOURCE}_{ENDPOINT}. Read this variable from apps that don’t use .NET service discovery.
services__orders__http__0The same URL, in the format that .NET service discovery reads.

AddSpringBootApp and AddQuarkusApp name their endpoint http. When you add an endpoint with a different name to a Java app, the variables use that name instead — for example, an endpoint named admin produces ORDERS_ADMIN. For the naming rules, see Endpoint URLs and Service discovery variables.

A Java app receives the variables of every resource that it references. In the preceding AppHost, orders receives CATALOG_HTTP and services__catalog__http__0 for the catalog app, and the connection properties of the ordersdb database, which include:

Environment variableDescription
ORDERSDB_JDBCCONNECTIONSTRINGThe JDBC URL, in the format jdbc:postgresql://{Host}:{Port}/{DatabaseName}. It doesn’t include the credentials.
ORDERSDB_USERNAMEThe user name for authentication.
ORDERSDB_PASSWORDThe password for authentication.
ORDERSDB_HOSTThe host name of the PostgreSQL server.
ORDERSDB_PORTThe port of the PostgreSQL server.
ORDERSDB_DATABASENAMEThe name of the database.

Each resource type documents its own connection properties, such as those in Connect to PostgreSQL. For the naming rules, see Resource properties.

The Java integration also sets the following variables on the Java app itself:

Environment variableSet onDescription
SERVER_PORTSpring Boot appsThe port that the app must listen on for its http endpoint. Spring Boot reads it as the server.port setting.
QUARKUS_HTTP_PORTQuarkus appsThe port that the app must listen on for its http endpoint. Quarkus reads it as the quarkus.http.port setting.
OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_SERVICE_NAME, and the other OTEL_* variablesAll Java resourcesWhere and how to export telemetry. For details, see OpenTelemetry environment variables.
QUARKUS_OTEL_EXPORTER_OTLP_ENDPOINT, QUARKUS_OTEL_SERVICE_NAME, and similar variablesQuarkus apps, when you run the AppHostCopies of the OpenTelemetry settings under the names that the Quarkus OpenTelemetry extension reads.
QUARKUS_PROFILE, QUARKUS_HTTP_HOST, and QUARKUS_OBSERVABILITY_ENABLEDQuarkus apps, when you run the AppHostDev mode settings. For details, see Add a Quarkus app.
JAVA_TOOL_OPTIONSJava resources that need JVM optionsThe options from WithJvmArgswithJvmArgs, the -javaagent option for the OpenTelemetry Java agent, and the development certificate trust store.

For an app that you add with AddJavaApp, the port variable is the one that you name with the env parameter of WithHttpEndpoint.

Apps call a Java app at the URL that Aspire injects. Each example calls the orders app from the storefront app in the preceding AppHost. Only the language differs.

In a project that uses the Aspire service defaults, .NET service discovery resolves the orders name from the services__orders__http__0 variable:

Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.AddServiceDefaults();
builder.Services.AddHttpClient("orders", client =>
{
client.BaseAddress = new Uri("https+http://orders");
});
var app = builder.Build();
app.MapGet("/orders", async (IHttpClientFactory factory) =>
{
var client = factory.CreateClient("orders");
return await client.GetStringAsync("/orders");
});
app.Run();

The https+http scheme prefers an HTTPS endpoint and falls back to HTTP. Without service discovery, read the URL from the ORDERS_HTTP configuration value instead.

Read Aspire configuration in your Java app

Section titled “Read Aspire configuration in your Java app”

There’s no Aspire client package for Java. A Java app reads the variables that Aspire injects through its framework’s standard configuration mechanism. Each example configures the orders app from the preceding AppHost to call the catalog app and to use the ordersdb database. Only the framework differs.

Spring Boot resolves environment variables in ${...} placeholders, so map the database variables to the standard datasource properties:

src/main/resources/application.properties
spring.datasource.url=${ORDERSDB_JDBCCONNECTIONSTRING}
spring.datasource.username=${ORDERSDB_USERNAME}
spring.datasource.password=${ORDERSDB_PASSWORD}

Inject the catalog app’s URL wherever you create a client:

src/main/java/com/example/orders/CatalogClient.java
package com.example.orders;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClient;
@Component
public class CatalogClient {
private final RestClient restClient;
public CatalogClient(
RestClient.Builder builder,
@Value("${CATALOG_HTTP:http://localhost:8080}") String catalogUrl) {
this.restClient = builder.baseUrl(catalogUrl).build();
}
public String products() {
return restClient.get()
.uri("/products")
.retrieve()
.body(String.class);
}
}

A default after the colon in a placeholder, such as http://localhost:8080 for CATALOG_HTTP, keeps the app runnable outside Aspire. Placeholders without a default make the app fail to start when the variable isn’t set.

Every Java resource receives the standard OpenTelemetry environment variables, but a JVM doesn’t export telemetry by itself. Use one of the following:

  • The OpenTelemetry Java agent. The agent reads the OTEL_* variables directly and instruments common libraries and frameworks without code changes. To attach it, see Attach the OpenTelemetry Java agent.
  • The Quarkus OpenTelemetry extension. When you run the AppHost, a Quarkus app added with AddQuarkusApp receives copies of the settings under the QUARKUS_OTEL_* names that the extension reads. A published app needs a mapping in application.properties, as described in Add a Quarkus app.

An app that uses neither doesn’t send telemetry to the dashboard, but its console output still appears in the dashboard’s console logs.

Aspire points each Java resource’s JVM at a trust store that contains the development certificate and the system’s root certificates, through JAVA_TOOL_OPTIONS. HTTP clients and database drivers that use the JVM’s default trust settings, such as java.net.http.HttpClient, therefore trust HTTPS endpoints that use the development certificate without any code changes. Code that builds its own SSLContext from a specific trust store doesn’t use Aspire’s trust store. For details, see Configure certificate trust.