This post explains some of the most useful Spring annotations with minimal code you can paste into a project. We’ll cover what each annotation does, when to use it, and a short example.
@EnableScheduling and @Scheduled #
- What they do
- @EnableScheduling: Turns on Spring’s scheduled task processing.
 - @Scheduled: Marks a method to run on a schedule.
 
 
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Configuration
@EnableScheduling
class SchedulingConfig { }
@Component
class ReportScheduler {
    // Runs every 5 seconds after previous start
    @Scheduled(fixedRate = 5_000)
    public void exportSummary() {
        System.out.println("exportSummary @ " + java.time.Instant.now());
    }
    // Cron: 09:00 Monday–Friday in Europe/Istanbul
    @Scheduled(cron = "0 0 9 * * MON-FRI", zone = "Europe/Istanbul")
    public void morningDigest() {
        System.out.println("morningDigest @ " + java.time.Instant.now());
    }
}
@EnableAsync and @Async #
- What they do
- @EnableAsync: Enables Spring’s async method execution infrastructure.
 - @Async: Runs a method on a separate thread (from a configured executor).
 
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
@Configuration
@EnableAsync
class AsyncConfig {
    @Bean(name = "taskExecutor")
    Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(4);
        executor.setMaxPoolSize(8);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("async-");
        executor.initialize();
        return executor;
    }
}
@Service
class EmailService {
    @Async("taskExecutor")
    public CompletableFuture<Void> sendWelcomeEmail(String to) {
        try {
            // simulate I/O
            Thread.sleep(500);
            System.out.println("sent welcome email to: " + to);
            return CompletableFuture.completedFuture(null);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return CompletableFuture.failedFuture(e);
        }
    }
}
@Component and @Service #
- What they do
- @Component: Generic stereotype to mark a class for component scanning.
 - @Service: Specialization of 
@Component, semantically indicating business logic. 
 
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
@Component
class SlugGenerator {
    String toSlug(String title) {
        return title.toLowerCase().replaceAll("[^a-z0-9]+", "-").replaceAll("(^-|-$)", "");
    }
}
@Service
class BlogService {
    private final SlugGenerator slugGenerator;
    BlogService(SlugGenerator slugGenerator) {
        this.slugGenerator = slugGenerator;
    }
    String createSlug(String title) {
        return slugGenerator.toSlug(title);
    }
}
@Configuration and @Bean #
- What they do
- @Configuration: Declares a class that defines beans via 
@Beanmethods. - @Bean: Declares a Spring bean returned by the annotated method.
 
 - @Configuration: Declares a class that defines beans via 
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;
import java.time.Clock;
@Configuration
class AppConfig {
    @Bean
    Clock clock() {
        return java.time.Clock.systemUTC();
    }
}
@Service
class TimeService {
    private final Clock clock;
    TimeService(Clock clock) {
        this.clock = clock;
    }
    java.time.Instant now() {
        return java.time.Instant.now(clock);
    }
}
Tips and gotchas #
- @Async self-invocation: Calls within the same class won’t go through the proxy, so 
@Asyncwon’t take effect. Call from another Spring bean. - @Async return types: Prefer 
CompletableFuture<T>for error handling. Forvoid, use anAsyncUncaughtExceptionHandlerif you need to observe errors. - Scheduling threads: Default scheduler is limited. For parallel schedules, define a 
TaskSchedulerbean or useThreadPoolTaskScheduler. - Cron time zone: Always set the 
zoneattribute if your business time zone differs from server time. - @Configuration vs @Component: Use 
@Configurationfor full configuration (ensures@Beanmethods return managed singletons even when called within the class).