As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.
Use interceptores de execução no AWS SDK for Java 2.x
Interceptores de execução inseridos AWS SDK for Java 2.x no ciclo de vida da solicitação e da resposta para executar a lógica personalizada em vários estágios da execução da chamada de API. Use interceptores para implementar questões transversais, como registro, coleta de métricas, modificação de solicitações, depuração e tratamento de erros.
Os interceptores implementam a ExecutionInterceptor
Ciclo de vida do interceptor
A ExecutionInterceptor
interface fornece métodos que são chamados em pontos específicos durante a execução da solicitação:
beforeExecution
- Chamado antes da execução da solicitaçãomodifyRequest
- Modifica o objeto de solicitação do SDKbeforeMarshalling
- Chamado antes da solicitação ser enviada para HTTPafterMarshalling
- Chamado após a solicitação ser enviada para HTTPmodifyHttpRequest
- Modifica a solicitação HTTPbeforeTransmission
- Chamado antes do envio da solicitação HTTPafterTransmission
- Chamado após o recebimento da resposta HTTPmodifyHttpResponse
- Modifica a resposta HTTPbeforeUnmarshalling
- Chamado antes que a resposta HTTP seja desorganizadaafterUnmarshalling
- Chamado após a desorganização da resposta HTTPmodifyResponse
- Modifica o objeto de resposta do SDKafterExecution
- Chamado após a execução bem-sucedida da solicitaçãoonExecutionFailure
- Chamado quando a execução da solicitação falha
Registre interceptores
Registre interceptores ao criar um cliente de serviço usando o overrideConfiguration
método. Você pode registrar vários interceptores e eles são executados na ordem em que você os registra.
// Register a single interceptor. SqsClient client = SqsClient.builder() .overrideConfiguration(c -> c.addExecutionInterceptor(new LoggingInterceptor())) .build(); // Register multiple interceptors. S3Client s3Client = S3Client.builder() .overrideConfiguration(config -> config .addExecutionInterceptor(new TimingInterceptor()) .addExecutionInterceptor(new LoggingInterceptor()) .addExecutionInterceptor(new RequestModificationInterceptor())) .build();
Exemplo de interceptor
A classe a seguir demonstra como usar interceptores de execução para adicionar questões transversais, como registro, monitoramento de desempenho e modificação de solicitações, às suas operações do S3 sem alterar sua lógica comercial principal.
Este exemplo mostra como registrar vários interceptores em um cliente S3 e vê-los em ação durante chamadas reais de AWS API.
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import software.amazon.awssdk.awscore.exception.AwsServiceException; import software.amazon.awssdk.core.ApiName; import software.amazon.awssdk.core.SdkRequest; import software.amazon.awssdk.core.interceptor.Context; import software.amazon.awssdk.core.interceptor.ExecutionAttributes; import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; import software.amazon.awssdk.http.SdkHttpRequest; import software.amazon.awssdk.http.SdkHttpResponse; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.HeadBucketRequest; import software.amazon.awssdk.services.s3.model.ListBucketsResponse; import java.time.Duration; import java.time.Instant;
public class S3InterceptorsDemo { private static final Logger logger = LoggerFactory.getLogger(S3InterceptorsDemo.class); public static void main(String[] args) { logger.info("=== AWS SDK for Java v2 - S3 Interceptors Demo ==="); // Create an S3 client with multiple interceptors. S3Client s3Client = S3Client.builder() .overrideConfiguration(config -> config .addExecutionInterceptor(new TimingInterceptor()) .addExecutionInterceptor(new LoggingInterceptor()) .addExecutionInterceptor(new RequestModificationInterceptor())) .build(); try { logger.info("Starting S3 operations with interceptors..."); // Operation 1: List buckets. logger.info("Operation 1: Listing S3 buckets"); logger.info("----------------------------------------"); ListBucketsResponse listBucketsResponse = s3Client.listBuckets(); logger.info("Found {} buckets", listBucketsResponse.buckets().size()); // Operation 2: Try to access a bucket that likely doesn't exist. logger.info("Operation 2: Checking non-existent bucket (demonstrating error interceptor)"); logger.info("----------------------------------------"); try { s3Client.headBucket(HeadBucketRequest.builder() .bucket("amzn-s3-demo-bucket-that-does-not-exist-1234") .build()); } catch (Exception e) { logger.info("Expected error occurred (interceptor should have logged it)"); } } catch (Exception e) { logger.error(" Error during S3 operations: {}", e.getMessage(), e); } finally { s3Client.close(); logger.info("Demo completed - S3 client closed"); } } // Logging interceptor. private static class LoggingInterceptor implements ExecutionInterceptor { private static final Logger logger = LoggerFactory.getLogger(LoggingInterceptor.class); @Override public void beforeExecution(Context.BeforeExecution context, ExecutionAttributes executionAttributes) { logger.info("[LOGGING] Starting request: {}", context.request().getClass().getSimpleName()); } @Override public void afterExecution(Context.AfterExecution context, ExecutionAttributes executionAttributes) { logger.info("[LOGGING] Completed request: {}", context.request().getClass().getSimpleName()); } @Override public void onExecutionFailure(Context.FailedExecution context, ExecutionAttributes executionAttributes) { logger.error("[LOGGING] Request failed: {}", context.request().getClass().getSimpleName()); if (context.exception() instanceof AwsServiceException) { AwsServiceException ase = (AwsServiceException) context.exception(); if (ase.awsErrorDetails().errorCode() != null) { SdkHttpResponse httpResponse = ase.awsErrorDetails().sdkHttpResponse(); logger.error(" HTTP Status: {}", httpResponse.statusCode()); logger.error(" Error Code: {}", ase.awsErrorDetails().errorCode()); logger.error(" Error Message: {}", ase.awsErrorDetails().errorMessage()); } } } } // Performance timing interceptor. private static class TimingInterceptor implements ExecutionInterceptor { private static final Logger logger = LoggerFactory.getLogger(TimingInterceptor.class); private Instant startTime; @Override public void beforeExecution(Context.BeforeExecution context, ExecutionAttributes executionAttributes) { startTime = Instant.now(); logger.info("⏱️ [TIMING] Request started at: {}", startTime); } @Override public void afterExecution(Context.AfterExecution context, ExecutionAttributes executionAttributes) { if (startTime != null) { Duration duration = Duration.between(startTime, Instant.now()); logger.info("⏱️ [TIMING] Request completed in: {}ms", duration.toMillis()); } } @Override public void onExecutionFailure(Context.FailedExecution context, ExecutionAttributes executionAttributes) { if (startTime != null) { Duration duration = Duration.between(startTime, Instant.now()); logger.warn("⏱️ [TIMING] Request failed after: {}ms", duration.toMillis()); } } } // Request modification interceptor private static class RequestModificationInterceptor implements ExecutionInterceptor { private static final Logger logger = LoggerFactory.getLogger(RequestModificationInterceptor.class); @Override public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) { SdkRequest originalRequest = context.request(); logger.info("[MODIFY] Modifying request: {}", originalRequest.getClass().getSimpleName()); // For ListBucketsRequest, we can't modify much since it has no settable properties // For HeadBucketRequest, we can demonstrate modifying the request if (originalRequest instanceof HeadBucketRequest) { HeadBucketRequest headRequest = (HeadBucketRequest) originalRequest; // Create a new request with an API name added. return HeadBucketRequest.builder() .bucket(headRequest.bucket()) .overrideConfiguration(b -> b.addApiName(ApiName.builder() .name("My-API") .version("1.0") .build())) .build(); } logger.info("Not a HeadBucketRequest, returning original request"); return originalRequest; } @Override public SdkHttpRequest modifyHttpRequest(Context.ModifyHttpRequest context, ExecutionAttributes executionAttributes) { logger.info("[MODIFY] Adding custom HTTP headers"); return context.httpRequest().toBuilder() .putHeader("X-Custom-Header", "S3InterceptorDemo") .putHeader("X-Request-ID", java.util.UUID.randomUUID().toString()) .build(); } } }
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>interceptors-examples</artifactId> <version>1.0.0</version> <packaging>jar</packaging> <name>interceptors-examples</name> <description>Demonstration of execution interceptors in AWS SDK for Java v2</description> <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <aws.java.sdk.version>2.31.62</aws.java.sdk.version> <exec.mainClass>org.example.S3InterceptorsDemo</exec.mainClass> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>bom</artifactId> <version>${aws.java.sdk.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-bom</artifactId> <version>2.23.1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>s3</artifactId> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>2.0.13</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j2-impl</artifactId> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-1.2-api</artifactId> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>5.10.1</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <!-- Compiler Plugin --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.11.0</version> <configuration> <source>17</source> <target>17</target> </configuration> </plugin> <!-- Surefire Plugin for running tests --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>3.2.2</version> </plugin> <!-- Exec Plugin for running the main class --> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>3.1.0</version> <configuration> <mainClass>${exec.mainClass}</mainClass> </configuration> </plugin> <!-- Shade Plugin to create executable JAR --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.4.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>${exec.mainClass}</mainClass> </transformer> </transformers> <createDependencyReducedPom>false</createDependencyReducedPom> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
Práticas recomendadas
-
Mantenha os interceptores leves: os interceptores são executados para cada solicitação, portanto, evite cálculos pesados ou operações de bloqueio que possam afetar o desempenho.
-
Lide com as exceções normalmente - Se o interceptor lançar uma exceção, isso fará com que toda a solicitação falhe. Sempre use blocos try-catch para operações potencialmente falhadas.
-
A ordem é importante - Os interceptores são executados na ordem em que você os registra. Considere as dependências entre seus interceptores ao registrá-los.
-
Use ExecutionAttributes para estado - Se você precisar passar dados entre diferentes métodos interceptores, use variáveis
ExecutionAttributes
em vez de instância para garantir a segurança do encadeamento. -
Cuidado com dados confidenciais - Ao registrar solicitações e respostas, tenha cuidado para não registrar informações confidenciais, como credenciais ou dados pessoais.
Objetos de contexto
Cada método interceptor recebe um objeto de contexto que fornece acesso às informações de solicitação e resposta em diferentes estágios de execução:
-
Context.BeforeExecution
- Fornece acesso à solicitação original do SDK -
Context.ModifyRequest
- Modifica a solicitação do SDK -
Context.ModifyHttpRequest
- Modifica a solicitação HTTP -
Context.AfterExecution
- Fornece acesso à solicitação e à resposta -
Context.FailedExecution
- Fornece acesso à solicitação e à exceção que ocorreu