

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

# Utilice interceptores de ejecución en AWS SDK for Java 2.x
<a name="interceptors"></a>

Los interceptores de ejecución de AWS SDK for Java 2.x se enlazan en el ciclo de vida de las solicitudes y las respuestas para realizar lógica personalizada en distintas etapas de la ejecución de las llamadas a la API. Utilice los interceptores para implementar aspectos transversales, como registro, recopilación de métricas, modificación de solicitudes, depuración y tratamiento de errores.

Los interceptores implementan la interfaz de [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/interceptor/ExecutionInterceptor.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/interceptor/ExecutionInterceptor.html), que proporciona enlaces para las diferentes fases de la ejecución de solicitudes.

## Ciclo de vida de los interceptores
<a name="interceptor-lifecycle"></a>

La interfaz de `ExecutionInterceptor` proporciona métodos a los que se llama en puntos específicos durante la ejecución de solicitudes:
+ `beforeExecution`: se llama antes de que se ejecute la solicitud
+ `modifyRequest`: modifica el objeto de solicitud del SDK
+ `beforeMarshalling`: se llama antes de que la solicitud se serialice a HTTP
+ `afterMarshalling`: se llama después de que la solicitud se serialice a HTTP
+ `modifyHttpRequest`: modifica la solicitud de HTTP
+ `beforeTransmission`: se llama antes de que se envíe la solicitud de HTTP
+ `afterTransmission`: se llama después de que se reciba la respuesta de HTTP
+ `modifyHttpResponse`: modifica la respuesta de HTTP
+ `beforeUnmarshalling`: se llama antes de que se deserialice la respuesta de HTTP
+ `afterUnmarshalling`: se llama después de que deserialice la respuesta de HTTP
+ `modifyResponse`: modifica el objeto de respuesta del SDK
+ `afterExecution`: se llama después de la ejecución correcta de la solicitud
+ `onExecutionFailure`: se llama cuando falla la ejecución de la solicitud

## Registro de interceptores
<a name="registering-interceptors"></a>

Registre interceptores al crear un cliente de servicio mediante el método `overrideConfiguration`. Puede registrar varios interceptores y se ejecutarán en el orden en el que los registre.

```
// 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();
```

## Ejemplo de interceptor
<a name="interceptor-examples"></a>

La siguiente clase demuestra cómo utilizar los interceptores de ejecución para añadir aspectos transversales como registro, supervisión del rendimiento y modificación de solicitudes a las operaciones de S3 sin cambiar la lógica empresarial principal.

En este ejemplo se muestra cómo registrar varios interceptores en un cliente de S3 y verlos en acción durante llamadas a la AWS API reales.

### Importaciones
<a name="interceptor-example-imports"></a>

```
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();
        }
    }
}
```

### Archivo pom de Maven
<a name="interceptor-example-pom"></a>

```
<?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ácticas recomendadas
<a name="interceptor-best-practices"></a>
+ **Mantenga los interceptores livianos**: los interceptores se ejecutan para cada solicitud, por lo que debe evitar computación intensa u operaciones de bloqueo que podrían afectar al rendimiento.
+ **Trate las excepciones con cuidado**: si el interceptor lanza una excepción, se produce un error en toda la solicitud. Utilice siempre bloques try-catch para operaciones que puedan fallar.
+ **Importancia del orden**: los interceptores se ejecutan en el orden en que los registra. Tenga en cuenta las dependencias entre los interceptores al registrarlos.
+ **Use ExecutionAttributes para el estado**: si necesita pasar datos entre diferentes métodos de interceptor, use `ExecutionAttributes` lugar de variables de instancia para garantizar la seguridad de los subprocesos.
+ **Preste atención a los datos confidenciales**: cuando registre solicitudes y respuestas, tenga cuidado de no registrar información confidencial, como credenciales o datos personales.

## Objetos de contexto
<a name="interceptor-context-objects"></a>

Cada método interceptor recibe un objeto de contexto que proporciona acceso a la información de solicitud y respuesta en diferentes etapas de ejecución:
+ `Context.BeforeExecution`: proporciona acceso a la solicitud original del SDK
+ `Context.ModifyRequest`: modifica la solicitud del SDK
+ `Context.ModifyHttpRequest`: modifica la solicitud de HTTP
+ `Context.AfterExecution`: proporciona acceso a la solicitud y la respuesta
+ `Context.FailedExecution`: proporciona acceso a la solicitud y a la excepción que se ha producido