Admin Sarwar 1 year ago
admin #java

Spring Boot Interview Questions

Spring Boot Interview Questions - Detailed Answers


1. Spring Boot Auto-Configuration MechanismQuestion: Explain the Spring Boot auto-configuration mechanism. How would you create a custom auto-configuration?Answer:

Auto-Configuration Process:

Spring Boot's auto-configuration works through the following mechanism:

  1. @EnableAutoConfiguration annotation triggers the auto-configuration process
  2. Spring Boot scans META-INF/spring.factories files in the classpath
  3. It loads all classes listed under org.springframework.boot.autoconfigure.EnableAutoConfiguration
  4. Each auto-configuration class uses conditional annotations to determine if it should be applied

Key Components:

// Example of how Spring Boot determines what to configure
@Configuration
@ConditionalOnClass(DataSource.class)
@ConditionalOnMissingBean(DataSource.class)
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {
    
    @Bean
    @ConditionalOnProperty(prefix = "spring.datasource", name = "url")
    public DataSource dataSource(DataSourceProperties properties) {
        return DataSourceBuilder.create()
            .url(properties.getUrl())
            .username(properties.getUsername())
            .password(properties.getPassword())
            .build();
    }
}

Creating Custom Auto-Configuration:

  1. Create Configuration Class:
@Configuration
@ConditionalOnClass(RedisTemplate.class)
@ConditionalOnMissingBean(RedisTemplate.class)
@EnableConfigurationProperties(CustomRedisProperties.class)
public class CustomRedisAutoConfiguration {
    
    @Bean
    public RedisTemplate<String, Object> redisTemplate(
            RedisConnectionFactory connectionFactory,
            CustomRedisProperties properties) {
        
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        
        // Custom serialization based on properties
        if (properties.isUseJsonSerialization()) {
            template.setDefaultSerializer(new GenericJackson2JsonRedisSerializer());
        }
        
        return template;
    }
}
  1. Create Properties Class:
@ConfigurationProperties(prefix = "custom.redis")
public class CustomRedisProperties {
    private boolean useJsonSerialization = true;
    private int maxConnections = 10;
    private Duration timeout = Duration.ofSeconds(5);
    
    // getters and setters
}
  1. Register in spring.factories:
# META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.autoconfigure.CustomRedisAutoConfiguration

Advanced Conditional Logic:

@Configuration
public class DatabaseAutoConfiguration {
    
    @Configuration
    @ConditionalOnProperty(value = "app.database.type", havingValue = "mysql")
    static class MySQLConfiguration {
        @Bean
        public DataSource mysqlDataSource() { /* implementation */ }
    }
    
    @Configuration
    @ConditionalOnProperty(value = "app.database.type", havingValue = "postgres")
    static class PostgreSQLConfiguration {
        @Bean
        public DataSource postgresDataSource() { /* implementation */ }
    }
}

2. Handling Circular DependenciesQuestion: How do you handle circular dependencies in Spring Boot? What are the different strategies?Answer:

Understanding Circular Dependencies:

Circular dependencies occur when Bean A depends on Bean B, and Bean B depends on Bean A, creating a cycle.

Detection:

// This creates a circular dependency
@Service
public class UserService {
    private final OrderService orderService;
    // UserService needs OrderService
}

@Service
public class OrderService {
    private final UserService userService;
    // OrderService needs UserService
}

Strategy 1: @Lazy Annotation

@Service
public class UserService {
    private final OrderService orderService;
    
    public UserService(@Lazy OrderService orderService) {
        this.orderService = orderService;
    }
}

@Service
public class OrderService {
    private final UserService userService;
    
    public OrderService(UserService userService) {
        this.userService = userService;
    }
}

Strategy 2: Setter Injection

@Service
public class UserService {
    private OrderService orderService;
    
    @Autowired
    public void setOrderService(OrderService orderService) {
        this.orderService = orderService;
    }
}

Strategy 3: ApplicationContextAware

@Service
public class UserService implements ApplicationContextAware {
    private ApplicationContext applicationContext;
    private OrderService orderService;
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
    
    private OrderService getOrderService() {
        if (orderService == null) {
            orderService = applicationContext.getBean(OrderService.class);
        }
        return orderService;
    }
}

Strategy 4: Restructuring (Best Practice)

// Extract common functionality to a separate service
@Service
public class BusinessLogicService {
    public void processUserOrder(User user, Order order) {
        // Common logic that both services need
    }
}

@Service
public class UserService {
    private final BusinessLogicService businessLogicService;
    
    public UserService(BusinessLogicService businessLogicService) {
        this.businessLogicService = businessLogicService;
    }
}

@Service
public class OrderService {
    private final BusinessLogicService businessLogicService;
    
    public OrderService(BusinessLogicService businessLogicService) {
        this.businessLogicService = businessLogicService;
    }
}

When to Use Each Strategy:

  • @Lazy: Quick fix, but can hide design issues
  • Setter Injection: Temporary solution, breaks immutability
  • ApplicationContextAware: More control, but couples to Spring
  • Restructuring: Best long-term solution, improves design

3. Microservices Distributed Transactions (Saga Pattern)Question: Design a distributed transaction strategy for microservices using Spring Boot. Compare Saga pattern vs 2PC.Answer:

Two-Phase Commit (2PC) vs Saga Pattern:

2PC Problems:

  • Blocking protocol (coordinator failure blocks all participants)
  • Not suitable for microservices (tight coupling)
  • Poor performance and availability

Saga Pattern Benefits:

  • Non-blocking
  • Better fault tolerance
  • Maintains service autonomy

Saga Implementation Types:


1. Choreography-Based Saga

// Order Service
@Service
public class OrderService {
    
    @EventListener
    public void handlePaymentProcessed(PaymentProcessedEvent event) {
        if (event.isSuccessful()) {
            // Continue with order processing
            confirmOrder(event.getOrderId());
            publishEvent(new OrderConfirmedEvent(event.getOrderId()));
        } else {
            // Compensate
            cancelOrder(event.getOrderId());
        }
    }
    
    private void confirmOrder(String orderId) {
        // Update order status
    }
    
    private void cancelOrder(String orderId) {
        // Compensation logic
    }
}

// Payment Service
@Service
public class PaymentService {
    
    @EventListener
    public void handleOrderCreated(OrderCreatedEvent event) {
        try {
            processPayment(event.getOrderId(), event.getAmount());
            publishEvent(new PaymentProcessedEvent(event.getOrderId(), true));
        } catch (PaymentException e) {
            publishEvent(new PaymentProcessedEvent(event.getOrderId(), false));
        }
    }
}

2. Orchestration-Based Saga

@Component
public class OrderSagaOrchestrator {
    
    private final PaymentService paymentService;
    private final InventoryService inventoryService;
    private final ShippingService shippingService;
    
    public void processOrder(OrderCreatedEvent event) {
        SagaTransaction saga = SagaTransaction.builder()
            .transactionId(event.getOrderId())
            .addStep(new PaymentStep(paymentService))
            .addStep(new InventoryStep(inventoryService))
            .addStep(new ShippingStep(shippingService))
            .build();
            
        saga.execute();
    }
}

// Saga Transaction Implementation
public class SagaTransaction {
    private final List<SagaStep> steps;
    private final List<SagaStep> completedSteps;
    
    public void execute() {
        try {
            for (SagaStep step : steps) {
                step.execute();
                completedSteps.add(step);
            }
        } catch (Exception e) {
            compensate();
            throw new SagaExecutionException("Saga failed", e);
        }
    }
    
    private void compensate() {
        // Execute compensation in reverse order
        Collections.reverse(completedSteps);
        for (SagaStep step : completedSteps) {
            try {
                step.compensate();
            } catch (Exception e) {
                log.error("Compensation failed for step: {}", step.getName(), e);
            }
        }
    }
}

// Abstract Saga Step
public abstract class SagaStep {
    public abstract void execute() throws Exception;
    public abstract void compensate() throws Exception;
    public abstract String getName();
}

// Concrete Implementation
public class PaymentStep extends SagaStep {
    private final PaymentService paymentService;
    
    @Override
    public void execute() throws Exception {
        paymentService.processPayment(getOrderId(), getAmount());
    }
    
    @Override
    public void compensate() throws Exception {
        paymentService.refundPayment(getOrderId());
    }
}

Saga State Management:

@Entity
public class SagaState {
    @Id
    private String sagaId;
    private String sagaType;
    private SagaStatus status;
    private String currentStep;
    private String compensationStep;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;
    
    @Convert(converter = JpaConverterJson.class)
    private Map<String, Object> sagaData;
}

@Repository
public interface SagaStateRepository extends JpaRepository<SagaState, String> {
    List<SagaState> findByStatusAndCreatedAtBefore(SagaStatus status, LocalDateTime dateTime);
}

Compensation Strategies:

  1. Semantic Rollback: Undo business operations (refund payment)
  2. Forward Recovery: Continue despite failures
  3. Retry with Exponential Backoff: Handle transient failures

Implementation Considerations:

  • Idempotency: All operations must be idempotent
  • Timeout Handling: Implement timeouts for each step
  • Monitoring: Track saga execution and failure rates
  • Dead Letter Queues: Handle failed compensations

4. Performance Optimization StrategyQuestion: Your Spring Boot application is experiencing high memory usage and slow response times. Walk through your debugging and optimization strategy.Answer:Phase 1: Diagnostics and Monitoring

1. Enable Comprehensive Monitoring:

# application.yml
management:
  endpoints:
    web:
      exposure:
        include: "*"
  metrics:
    export:
      prometheus:
        enabled: true
  endpoint:
    health:
      show-details: always

2. Memory Analysis Tools:

@RestController
public class DiagnosticsController {
    
    @GetMapping("/diagnostics/memory")
    public Map<String, Object> getMemoryInfo() {
        Runtime runtime = Runtime.getRuntime();
        Map<String, Object> memInfo = new HashMap<>();
        
        memInfo.put("totalMemory", runtime.totalMemory());
        memInfo.put("freeMemory", runtime.freeMemory());
        memInfo.put("usedMemory", runtime.totalMemory() - runtime.freeMemory());
        memInfo.put("maxMemory", runtime.maxMemory());
        
        // GC Information
        List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans();
        for (GarbageCollectorMXBean gcBean : gcBeans) {
            memInfo.put(gcBean.getName() + "_collections", gcBean.getCollectionCount());
            memInfo.put(gcBean.getName() + "_time", gcBean.getCollectionTime());
        }
        
        return memInfo;
    }
}

Phase 2: Common Performance Issues and Solutions

1. Database Query Optimization:

// Problem: N+1 Query Issue
@Entity
public class User {
    @OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
    private List<Order> orders;
}

// Solution: Use @EntityGraph or JOIN FETCH
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    
    @EntityGraph(attributePaths = {"orders"})
    @Query("SELECT u FROM User u WHERE u.active = true")
    List<User> findActiveUsersWithOrders();
    
    // Or use custom query
    @Query("SELECT u FROM User u LEFT JOIN FETCH u.orders WHERE u.active = true")
    List<User> findActiveUsersWithOrdersJoinFetch();
}

2. Connection Pool Optimization:

spring:
  datasource:
    hikari:
      maximum-pool-size: 20
      minimum-idle: 5
      idle-timeout: 300000
      max-lifetime: 1200000
      connection-timeout: 20000
      validation-timeout: 3000
      leak-detection-threshold: 60000

3. Caching Strategy:

@Configuration
@EnableCaching
public class CacheConfig {
    
    @Bean
    public CacheManager cacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        cacheManager.setCaffeine(Caffeine.newBuilder()
            .maximumSize(1000)
            .expireAfterWrite(10, TimeUnit.MINUTES)
            .recordStats());
        return cacheManager;
    }
}

@Service
public class UserService {
    
    @Cacheable(value = "users", key = "#id")
    public User findById(Long id) {
        return userRepository.findById(id).orElse(null);
    }
    
    @CacheEvict(value = "users", key = "#user.id")
    public User updateUser(User user) {
        return userRepository.save(user);
    }
}

4. Async Processing:

@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
    
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(20);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("async-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

@Service
public class NotificationService {
    
    @Async
    public CompletableFuture<Void> sendEmailAsync(String email, String message) {
        // Long-running email sending process
        emailSender.send(email, message);
        return CompletableFuture.completedFuture(null);
    }
}

Phase 3: JVM Tuning

1. Memory Configuration:

# Production JVM settings
java -Xms2g -Xmx4g \
     -XX:+UseG1GC \
     -XX:MaxGCPauseMillis=200 \
     -XX:+UseStringDeduplication \
     -XX:+UseCompressedOops \
     -XX:+UseCompressedClassPointers \
     -jar application.jar

2. Garbage Collection Monitoring:

@Component
public class GCMonitor {
    
    @EventListener
    public void handleContextRefresh(ContextRefreshedEvent event) {
        // Register GC notification listener
        List<GarbageCollectorMXBean> gcbeans = ManagementFactory.getGarbageCollectorMXBeans();
        for (GarbageCollectorMXBean gcbean : gcbeans) {
            NotificationEmitter emitter = (NotificationEmitter) gcbean;
            emitter.addNotificationListener(this::handleGCNotification, null, null);
        }
    }
    
    private void handleGCNotification(Notification notification, Object handback) {
        if (notification.getType().equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION)) {
            GarbageCollectionNotificationInfo info = 
                GarbageCollectionNotificationInfo.from((CompositeData) notification.getUserData());
                
            // Log or alert on long GC pauses
            if (info.getGcInfo().getDuration() > 1000) {
                log.warn("Long GC pause detected: {} ms", info.getGcInfo().getDuration());
            }
        }
    }
}

Phase 4: Application-Level Optimizations

1. Lazy Loading Configuration:

@Configuration
public class OptimizationConfig {
    
    @Bean
    @Lazy
    public ExpensiveService expensiveService() {
        return new ExpensiveService();
    }
}

2. Response Compression:

server:
  compression:
    enabled: true
    mime-types: text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json
    min-response-size: 1024

3. Database Batch Operations:

@Service
public class BatchUserService {
    
    @Transactional
    public void saveUsers(List<User> users) {
        int batchSize = 50;
        for (int i = 0; i < users.size(); i += batchSize) {
            List<User> batch = users.subList(i, Math.min(i + batchSize, users.size()));
            userRepository.saveAll(batch);
            
            // Flush and clear to prevent memory issues
            entityManager.flush();
            entityManager.clear();
        }
    }
}

Monitoring and Alerting Setup:

@Component
public class PerformanceMetrics {
    
    private final MeterRegistry meterRegistry;
    private final Timer responseTimer;
    private final Counter errorCounter;
    
    public PerformanceMetrics(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
        this.responseTimer = Timer.builder("http.request.duration")
            .description("HTTP request duration")
            .register(meterRegistry);
        this.errorCounter = Counter.builder("http.request.errors")
            .description("HTTP request errors")
            .register(meterRegistry);
    }
    
    @EventListener
    public void handleHttpRequest(HttpRequestEvent event) {
        responseTimer.record(event.getDuration(), TimeUnit.MILLISECONDS);
        if (event.isError()) {
            errorCounter.increment();
        }
    }
}

This comprehensive approach addresses both immediate performance issues and establishes long-term monitoring and optimization practices.



5. Security Architecture - Zero Trust ImplementationQuestion: Design a zero-trust security architecture for Spring Boot microservices. How would you implement service-to-service authentication without a central auth server?Answer:

Zero Trust Principles:

  1. Never trust, always verify
  2. Assume breach has occurred
  3. Verify explicitly for every transaction
  4. Use least-privilege access

Implementation Strategy:

1. Mutual TLS (mTLS) for Service Authentication:

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    
    @Bean
    public WebSecurityConfigurerAdapter webSecurityConfig() {
        return new WebSecurityConfigurerAdapter() {
            @Override
            protected void configure(HttpSecurity http) throws Exception {
                http
                    .requiresChannel(channel -> 
                        channel.requestMatchers(r -> r.getHeader("X-Forwarded-Proto") != null)
                               .requiresSecure())
                    .x509(x509 -> x509
                        .subjectPrincipalRegex("CN=(.*?)(?:,|$)")
                        .userDetailsService(customX509UserDetailsService()))
                    .authorizeRequests(authz -> authz
                        .requestMatchers("/actuator/health").permitAll()
                        .requestMatchers("/internal/**").hasRole("SERVICE")
                        .anyRequest().authenticated())
                    .sessionManagement(session -> 
                        session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
            }
        };
    }
    
    @Bean
    public X509UserDetailsService customX509UserDetailsService() {
        return new X509UserDetailsService() {
            @Override
            public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
                // Validate service identity from certificate CN
                if (isValidServiceIdentity(username)) {
                    return User.builder()
                        .username(username)
                        .password("")
                        .roles("SERVICE")
                        .build();
                }
                throw new UsernameNotFoundException("Invalid service identity: " + username);
            }
        };
    }
}

2. JWT with Service Identity Claims:

@Component
public class ServiceTokenManager {
    
    private final String privateKey;
    private final Map<String, String> trustedServices;
    
    public String generateServiceToken(String serviceId, String targetService) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("service_id", serviceId);
        claims.put("target_service", targetService);
        claims.put("permissions", getServicePermissions(serviceId, targetService));
        claims.put("issued_at", System.currentTimeMillis());
        
        return Jwts.builder()
            .setClaims(claims)
            .setIssuer(serviceId)
            .setAudience(targetService)
            .setExpiration(Date.from(Instant.now().plusSeconds(300))) // 5 minutes
            .signWith(SignatureAlgorithm.RS256, getPrivateKey())
            .compact();
    }
    
    public boolean validateServiceToken(String token, String expectedService) {
        try {
            Claims claims = Jwts.parser()
                .setSigningKey(getPublicKey(getServiceIdFromToken(token)))
                .parseClaimsJws(token)
                .getBody();
                
            String serviceId = claims.get("service_id", String.class);
            String targetService = claims.get("target_service", String.class);
            
            return trustedServices.containsKey(serviceId) && 
                   expectedService.equals(targetService) &&
                   hasValidPermissions(claims);
                   
        } catch (JwtException e) {
            log.warn("Invalid service token: {}", e.getMessage());
            return false;
        }
    }
}

3. Request Signing for Message Integrity:

@Component
public class RequestSigningInterceptor implements ClientHttpRequestInterceptor {
    
    private final String serviceId;
    private final PrivateKey privateKey;
    
    @Override
    public ClientHttpResponse intercept(
            HttpRequest request, 
            byte[] body, 
            ClientHttpRequestExecution execution) throws IOException {
        
        // Create signature
        String timestamp = String.valueOf(System.currentTimeMillis());
        String nonce = UUID.randomUUID().toString();
        String stringToSign = createStringToSign(request, body, timestamp, nonce);
        String signature = signString(stringToSign);
        
        // Add headers
        request.getHeaders().add("X-Service-ID", serviceId);
        request.getHeaders().add("X-Timestamp", timestamp);
        request.getHeaders().add("X-Nonce", nonce);
        request.getHeaders().add("X-Signature", signature);
        
        return execution.execute(request, body);
    }
    
    private String createStringToSign(HttpRequest request, byte[] body, 
                                     String timestamp, String nonce) {
        return String.join("\n",
            request.getMethod().name(),
            request.getURI().getPath(),
            request.getURI().getQuery() != null ? request.getURI().getQuery() : "",
            timestamp,
            nonce,
            DigestUtils.sha256Hex(body)
        );
    }
}

4. Distributed Authorization with Policy Engine:

@Service
public class PolicyEngine {
    
    private final PolicyRepository policyRepository;
    
    public boolean authorize(ServiceRequest request) {
        String serviceId = request.getServiceId();
        String resource = request.getResource();
        String action = request.getAction();
        
        List<Policy> policies = policyRepository.findByServiceId(serviceId);
        
        for (Policy policy : policies) {
            if (policy.matches(resource, action)) {
                return evaluatePolicy(policy, request);
            }
        }
        
        return false; // Deny by default
    }
    
    private boolean evaluatePolicy(Policy policy, ServiceRequest request) {
        // Implement policy evaluation logic
        // Support for RBAC, ABAC, time-based access, etc.
        
        for (PolicyCondition condition : policy.getConditions()) {
            if (!condition.evaluate(request.getContext())) {
                return false;
            }
        }
        
        return true;
    }
}

@Entity
public class Policy {
    @Id
    private String id;
    private String serviceId;
    private String resourcePattern;
    private String actionPattern;
    private PolicyEffect effect; // ALLOW, DENY
    
    @OneToMany(mappedBy = "policy", cascade = CascadeType.ALL)
    private List<PolicyCondition> conditions;
    
    public boolean matches(String resource, String action) {
        return resource.matches(resourcePattern) && 
               action.matches(actionPattern);
    }
}

5. Network Segmentation and Service Mesh Integration:

@Configuration
public class ServiceMeshConfig {
    
    @Bean
    public RestTemplate secureRestTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        
        // Add interceptors for service mesh integration
        restTemplate.getInterceptors().add(new ServiceMeshHeaderInterceptor());
        restTemplate.getInterceptors().add(new RequestSigningInterceptor());
        restTemplate.getInterceptors().add(new CircuitBreakerInterceptor());
        
        return restTemplate;
    }
}

@Component
public class ServiceMeshHeaderInterceptor implements ClientHttpRequestInterceptor {
    
    private final String serviceId = System.getenv("SERVICE_ID");
    private final String podId = System.getenv("HOSTNAME");
    
    @Override
    public ClientHttpResponse intercept(
            HttpRequest request, 
            byte[] body, 
            ClientHttpRequestExecution execution) throws IOException {
        
        // Add service mesh headers
        request.getHeaders().add("X-Service-Source", serviceId);
        request.getHeaders().add("X-Pod-ID", podId);
        request.getHeaders().add("X-Trace-ID", getCurrentTraceId());
        
        return execution.execute(request, body);
    }
}

6. Runtime Security Monitoring:

@Component
public class SecurityMonitor {
    
    private final MeterRegistry meterRegistry;
    private final Counter authFailures;
    private final Counter suspiciousActivity;
    
    public SecurityMonitor(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
        this.authFailures = Counter.builder("security.auth.failures")
            .description("Authentication failures")
            .register(meterRegistry);
        this.suspiciousActivity = Counter.builder("security.suspicious.activity")
            .description("Suspicious activity detected")
            .register(meterRegistry);
    }
    
    @EventListener
    public void handleAuthenticationFailure(AuthenticationFailureEvent event) {
        authFailures.increment(
            Tags.of(
                "source", event.getSource(),
                "reason", event.getException().getClass().getSimpleName()
            )
        );
        
        // Trigger security response if needed
        if (isRepeatedFailure(event.getSource())) {
            triggerSecurityResponse(event.getSource());
        }
    }
    
    private void triggerSecurityResponse(String source) {
        // Implement automated response
        // - Block IP/service temporarily
        // - Alert security team
        // - Increase monitoring
    }
}

Benefits of this approach:

  • No single point of failure: No central auth server dependency
  • Defense in depth: Multiple security layers
  • Service autonomy: Each service validates independently
  • Audit trail: Comprehensive logging and monitoring
  • Scalable: Distributed policy evaluation

Challenges and Mitigations:

  • Certificate management: Use automated certificate rotation
  • Policy consistency: Implement policy validation and testing
  • Performance impact: Cache validation results appropriately
  • Complexity: Provide clear documentation and tooling

6. Event Sourcing System DesignQuestion: Design an event sourcing system using Spring Boot. How would you handle event versioning, snapshots, and replay mechanisms?Answer:

Event Sourcing Fundamentals: Event sourcing stores all changes to application state as a sequence of events, rather than storing current state directly.

Core Implementation:

1. Event Store Design:

@Entity
@Table(name = "event_store")
public class EventEntity {
    @Id
    private String eventId;
    
    private String aggregateId;
    private String aggregateType;
    private Long version;
    private String eventType;
    private String eventData;
    private String metadata;
    private LocalDateTime timestamp;
    private String userId;
    
    // Optimistic locking
    @Version
    private Long entityVersion;
}

@Repository
public interface EventRepository extends JpaRepository<EventEntity, String> {
    
    @Query("SELECT e FROM EventEntity e WHERE e.aggregateId = :aggregateId ORDER BY e.version")
    List<EventEntity> findByAggregateIdOrderByVersion(@Param("aggregateId") String aggregateId);
    
    @Query("SELECT e FROM EventEntity e WHERE e.aggregateId = :aggregateId AND e.version > :fromVersion ORDER BY e.version")
    List<EventEntity> findByAggregateIdAndVersionGreaterThan(@Param("aggregateId") String aggregateId, 
                                                            @Param("fromVersion") Long fromVersion);
    
    @Query("SELECT e FROM EventEntity e WHERE e.timestamp >= :fromTime ORDER BY e.timestamp")
    Stream<EventEntity> findEventsFromTime(@Param("fromTime") LocalDateTime fromTime);
}

2. Aggregate Root with Event Sourcing:

public abstract class AggregateRoot {
    private String id;
    private Long version = 0L;
    private List


0
199
PLSQL With Oracle JSON Data

PLSQL With Oracle JSON Data

1723130013.png
Admin Sarwar
2 years ago

How do you execute raw SQL queries in Entity Framework?

How do you execute raw SQL queries in Entity Framework?

1723130013.png
Admin Sarwar
1 year ago

The term 'gcc' is not recognized as the name of a cmdlet, function...

The term 'gcc' is not recognized as the name of a cmdlet, function... C , C++ compiler n...

1723130013.png
Admin Sarwar
1 year ago
Kiddie Comic GPT Builder Review (2026): Honest Look Before You Buy

Kiddie Comic GPT Builder Review (2026): Honest Look Before You Buy

1723130013.png
Admin Sarwar
1 month ago

Kanniloru Minnal

Kanniloru Minnal

1723130013.png
Admin Sarwar
8 months ago