Spring Application Optimizations:
@Async
WebClient
for async inter-service REST API calls over sync RestClient
JpaRepository
, CrudRepository
)-XX:+UseZGC
) and size of the heap (-Xms512m -Xmx2g
; initial and max size)If anything goes wrong, debug using Actuator (/metrics
) and other Micrometer observability stats. Detect deadlocks and concurrency issues by analyzing thread dumps with tools like jstack
, jvisualvm
, or IntelliJ Profiler (Ultimate Edition only).
Async processing in Spring Boot: we can use @Async
annotation provided in Spring Boot instead of writing our own CompletableFutures everytime. notes
List all beans in a Spring Boot application:
@Autowired
private ApplicationContext applicationContext; // this contains every info about the app
public void listBeans{
for(String beanName : applicationContext.getBeanDefinitionNames()){
System.out.println(beanName);
}
}
Alternatively, actuator’s /beans
endpoint can also list all beans, need to expose it first though.
YAML vs Properties: YAML is cleaner and structured, properties is simple and verbose. YAML files cannot be loaded by using the @PropertySource
annotation so that’s a negative.
How to disable a specific Auto-Configuration?: find out the configuration class that configures the functionality and use exclude
property in main class annotation.
@SpringBootApplication(exclude = {"DataSourceAutoConfiguration.class"})
public class MyApplication{
public static void main(String[] args){
SpringApplication.run(MyApplication.class, args);
}
}
Override a method on a class imported from JAR dependency: create a subclass and override the method (overrides on parent class ref too) and declare a custom bean of original type in a config class with the same name @Bean("")
or use @Primary
. We should try to avoid changing code too much here since original class maybe autowired at multiple places in the code hence @Qualifier
isn’t a good solution here.
// original class autowired in multiple places in existing code
@Autowired
OriginalClass originalClass;
// original class bean
@Component
public class OriginalClass {
@Override
public void methodToOverride() {
System.out.println("Original implementation");
}
}
// create a custom class
public class CustomClass extends OriginalClass {
@Override
public void methodToOverride() {
System.out.println("Custom implementation");
}
}
// config class with bean override
@Configuration
public class CustomConfiguration {
@Bean("originalClass") // same name as the original class (bean overriding)
@Primary // alternatively we can mark it as primary (better way; bean selection)
public OriginalClass customClass() {
return new CustomClass();
}
}
// ensure proper component scan in Spring so that our custom bean is picked up
// our custom bean will override the original bean from the JAR if it has the same name
// alternatively if we mark it using the @Primary annotation, it ensures that if there are multiple beans of the same type, Spring will prefer the custom bean even if names are diff
WITH (NOLOCK)
clause to write queries, equivalent to setting READ_UNCOMMITED
isolation level on transactions.LIMIT
and OFFSET
) as well, caching at controller level, implemented relevant code as async processingScaling for high traffic:
Calling other services: be async (use WebFlux’s WebClient), implement circuit breaker, rate limit with exponential backoff, and cache responses to reduce network requests.
Event-driven architecture: for intra-app event driven communication we can use events API provided in Spring. notes
Soft Delete: mark rows as delted = true
in a boolean column. On reads, filter out these marked rows from the output.
Async vs Event-Driven Processing: in async we’ve direct control over when and by whom tasks are executed (parallel aka non-blocking). In event-driven we decouple and allow reaction to events. Often made parallel too, in which case its called event-driven non-blocking processing (Reactive).