How do I launch a coroutine in Kotlin using launch and runBlocking?

In Kotlin, you can use runBlocking to start a coroutine scope that blocks the current thread until its coroutines finish, and launch to start a new coroutine inside that scope.

import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

fun main() = runBlocking {
    launch {
        println("Coroutine is running")
    }

    println("Main coroutine continues")
}

Output may look like:

Main coroutine continues
Coroutine is running

runBlocking creates a coroutine and blocks the current thread until all child coroutines complete.

launch starts a new coroutine that runs concurrently with the rest of the code inside the runBlocking scope.

A slightly clearer example:

import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

fun main() = runBlocking {
    launch {
        delay(1000)
        println("World!")
    }

    println("Hello")
}

Output:

Hello
World!

Here:

  • runBlocking { ... } starts a blocking coroutine scope.
  • launch { ... } starts a child coroutine.
  • delay(1000) suspends the coroutine for 1 second without blocking the thread.
  • runBlocking waits until the launched coroutine finishes before main exits.

How do I use external configuration with Spring?

External configuration means keeping settings such as application names, URLs, ports, feature flags, credentials, or environment-specific values outside your Java code.

Spring supports this mainly through:

  • application.properties
  • application.yml
  • environment variables
  • command-line arguments
  • external property files
  • @Value
  • @ConfigurationProperties

1. Using application.properties

In a Spring or Spring Boot application, you can place configuration in:

src/main/resources/application.properties

Example:

app.name=My Spring App
app.version=1.0.0
app.description=Example application using external configuration

Then inject values with @Value:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class AppProperties {

    @Value("${app.name}")
    private String appName;

    @Value("${app.version}")
    private String appVersion;

    @Value("${app.description}")
    private String appDescription;

    public void printProperties() {
        System.out.println("App Name: " + appName);
        System.out.println("App Version: " + appVersion);
        System.out.println("App Description: " + appDescription);
    }
}

2. Using application.yml

You can also use YAML:

app:
  name: My Spring App
  version: 1.0.0
  description: Example application using external configuration

The same @Value expressions still work:

@Value("${app.name}")
private String appName;

3. Using @PropertySource in non-Boot Spring

If you are using plain Spring with Java configuration, register a property file using @PropertySource:

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Configuration
@ComponentScan("com.example.app")
@PropertySource("classpath:application.properties")
public class AppConfig {
}

Then Spring can resolve values like:

@Value("${app.name}")
private String appName;

If you are using Spring Boot, you usually do not need @PropertySource for application.properties or application.yml. Spring Boot loads them automatically.


4. Recommended Spring Boot Approach: @ConfigurationProperties

For multiple related properties, prefer @ConfigurationProperties over many @Value fields.

Example application.properties:

app.name=My Spring App
app.version=1.0.0
app.description=Example application using external configuration

Create a properties class:

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "app")
public class AppProperties {

    private String name;
    private String version;
    private String description;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

Then inject it into another bean:

import org.springframework.stereotype.Service;

@Service
public class GreetingService {

    private final AppProperties appProperties;

    public GreetingService(AppProperties appProperties) {
        this.appProperties = appProperties;
    }

    public void printGreeting() {
        System.out.println("Welcome to " + appProperties.getName());
        System.out.println("Version: " + appProperties.getVersion());
        System.out.println(appProperties.getDescription());
    }
}

5. External Files Outside the JAR

You can override configuration from outside the application.

For Spring Boot:

java -jar myapp.jar --spring.config.location=file:/opt/myapp/application.properties

Or include an additional config file:

java -jar myapp.jar --spring.config.additional-location=file:/opt/myapp/

Example external file:

app.name=Production App
app.version=2.0.0
app.description=Running with production configuration

6. Environment Variables

Spring Boot can read environment variables automatically.

For example, this property:

app.name=My Spring App

Can be overridden with:

APP_NAME=Production App

Spring Boot maps environment variable names to property names using relaxed binding:

APP_NAME -> app.name
SERVER_PORT -> server.port
SPRING_DATASOURCE_URL -> spring.datasource.url

7. Command-Line Arguments

You can override properties when starting the application:

java -jar myapp.jar --app.name="Command Line App" --server.port=9090

Command-line arguments usually have high priority and override values from property files.


8. Profiles for Environment-Specific Config

Profiles let you separate configuration by environment.

Common files:

application.properties
application-dev.properties
application-test.properties
application-prod.properties

Example:

# application-prod.properties
app.name=Production App
server.port=8080

Run with a profile:

java -jar myapp.jar --spring.profiles.active=prod

Or set an environment variable:

SPRING_PROFILES_ACTIVE=prod

9. Default Values with @Value

You can provide fallback values:

@Value("${app.name:Default App}")
private String appName;

If app.name is missing, Spring uses "Default App".


10. Common Property Examples

server.port=8081

spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.username=myuser
spring.datasource.password=secret

logging.level.org.springframework=INFO

app.name=My Spring App
app.version=1.0.0

Summary

Use external configuration like this:

Use case Recommended approach
Simple single value @Value("${property.name}")
Group of related settings @ConfigurationProperties
Spring Boot default config application.properties or application.yml
Plain Spring Java config @PropertySource
Environment-specific config Spring profiles
Production overrides external file, environment variables, or command-line args

For most Spring Boot applications, the usual setup is:

src/main/resources/application.properties

plus a configuration class using:

@ConfigurationProperties(prefix = "app")

This keeps configuration clean, type-safe, and easy to override per environment.

How do I manage bean scope in Spring?

In Spring, bean scope controls how many instances of a bean Spring creates and how long those instances live.

By default, Spring beans are singleton scoped, meaning Spring creates one shared instance per ApplicationContext.


Common Spring Bean Scopes

Scope Meaning
singleton One shared instance per Spring container
prototype A new instance every time the bean is requested
request One instance per HTTP request
session One instance per HTTP session
application One instance per ServletContext
websocket One instance per WebSocket session

The most commonly used scopes are:

  • singleton
  • prototype
  • request
  • session

1. Singleton Scope

singleton is the default scope.

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

@Service
@Scope("singleton")
public class UserService {
}

This is equivalent to:

import org.springframework.stereotype.Service;

@Service
public class UserService {
}

Spring creates only one UserService object, and every injection point receives the same instance.


Example

@Service
public class CounterService {

    private int count = 0;

    public int increment() {
        return ++count;
    }
}

Because this bean is singleton scoped, the count field is shared across the application.

That means singleton beans should usually be stateless, especially in web applications.

Prefer this:

@Service
public class PriceCalculator {

    public BigDecimal calculatePrice(BigDecimal amount) {
        return amount.multiply(new BigDecimal("1.10"));
    }
}

Avoid storing request-specific or user-specific data in singleton beans.


2. Prototype Scope

A prototype bean creates a new instance every time Spring is asked for the bean.

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("prototype")
public class ReportBuilder {

    private String title;

    public void setTitle(String title) {
        this.title = title;
    }

    public String build() {
        return "Report: " + title;
    }
}

Each direct request to Spring for ReportBuilder creates a new object.


Prototype with @Bean

You can also define prototype scope on a @Bean method:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

@Configuration
public class AppConfig {

    @Bean
    @Scope("prototype")
    public ReportBuilder reportBuilder() {
        return new ReportBuilder();
    }
}

3. Important: Prototype Inside Singleton

A common surprise is this:

@Service
public class ReportService {

    private final ReportBuilder reportBuilder;

    public ReportService(ReportBuilder reportBuilder) {
        this.reportBuilder = reportBuilder;
    }
}

If ReportService is singleton and ReportBuilder is prototype, Spring injects one prototype instance when ReportService is created.

It does not automatically create a new ReportBuilder every time you use it.


Correct Way: Use ObjectProvider

If a singleton needs a fresh prototype instance on demand, use ObjectProvider.

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.stereotype.Service;

@Service
public class ReportService {

    private final ObjectProvider<ReportBuilder> reportBuilderProvider;

    public ReportService(ObjectProvider<ReportBuilder> reportBuilderProvider) {
        this.reportBuilderProvider = reportBuilderProvider;
    }

    public String createReport(String title) {
        ReportBuilder builder = reportBuilderProvider.getObject();
        builder.setTitle(title);
        return builder.build();
    }
}

Now each call to getObject() returns a new prototype instance.


4. Request Scope

request scope creates one bean instance per HTTP request.

This is useful in Spring MVC applications for request-specific data.

import org.springframework.stereotype.Component;
import org.springframework.web.context.annotation.RequestScope;

@Component
@RequestScope
public class RequestContext {

    private String correlationId;

    public String getCorrelationId() {
        return correlationId;
    }

    public void setCorrelationId(String correlationId) {
        this.correlationId = correlationId;
    }
}

Each HTTP request gets its own RequestContext.


5. Session Scope

session scope creates one bean instance per HTTP session.

import org.springframework.stereotype.Component;
import org.springframework.web.context.annotation.SessionScope;

@Component
@SessionScope
public class ShoppingCart {

    private final List<String> items = new ArrayList<>();

    public void addItem(String item) {
        items.add(item);
    }

    public List<String> getItems() {
        return items;
    }
}

Each user session gets its own ShoppingCart.

This is useful for things like:

  • shopping carts
  • user preferences
  • wizard-style form state

6. Using Scope Constants

Instead of writing scope names as strings, you can use Spring constants.

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ReportBuilder {
}

For singleton:

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

@Service
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public class UserService {
}

7. XML Configuration Example

If you use XML configuration, define the scope with the scope attribute.

Singleton

<bean id="service" class="com.example.DummyService" scope="singleton"/>

Since singleton is the default, this is also valid:

<bean id="service" class="com.example.DummyService"/>

Prototype

<bean id="service" class="com.example.DummyService" scope="prototype"/>

With singleton scope, repeated calls to getBean("service") return the same object.

With prototype scope, repeated calls to getBean("service") return different objects.


8. Lifecycle Difference

Singleton beans are fully managed by Spring, including destruction callbacks.

import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.springframework.stereotype.Service;

@Service
public class CacheService {

    @PostConstruct
    public void init() {
        System.out.println("Cache initialized");
    }

    @PreDestroy
    public void shutdown() {
        System.out.println("Cache shutting down");
    }
}

For singleton beans:

  • Spring creates the bean
  • Spring initializes it
  • Spring calls destruction callbacks when the context closes

For prototype beans:

  • Spring creates and initializes the bean
  • Spring does not manage the full destruction lifecycle after handing it out

So if a prototype bean holds resources, your application is responsible for cleanup.


9. Choosing the Right Scope

Use this as a practical guide:

Use case Recommended scope
Stateless service singleton
Repository/data access object singleton
Controller usually singleton
Stateful object created per use prototype
Request-specific data request
User-session data session

Best Practices

  1. Keep singleton beans stateless when possible.
  2. Do not store user-specific data in singleton services.
  3. Use prototype for objects that need independent state per use.
  4. Use ObjectProvider<T> when a singleton needs fresh prototype instances.
  5. Use @RequestScope for per-request web data.
  6. Use @SessionScope carefully, because session state consumes memory.
  7. Prefer annotation-based configuration in modern Spring applications.
  8. Use XML scope configuration only when working with XML-based Spring setup.

Bottom Line

You manage bean scope in Spring by declaring the scope on the bean:

@Component
@Scope("prototype")
public class MyBean {
}

or:

@Bean
@Scope("prototype")
public MyBean myBean() {
    return new MyBean();
}

If you do not specify a scope, Spring uses:

singleton

So in most applications, services, repositories, and controllers are singleton beans, while stateful per-use objects should be prototype, request, or session scoped depending on how long their state should live.

How do I inject dependencies using constructor injection?

Use constructor injection by declaring your dependency as a private final field and accepting it as a constructor parameter. Spring will create the dependency bean and pass it into the constructor automatically.

Example:

import org.springframework.stereotype.Component;

@Component
public class MyDependency {

    public void doSomething() {
        System.out.println("Dependency logic executed.");
    }
}
import org.springframework.stereotype.Service;

@Service
public class MyService {

    private final MyDependency myDependency;

    public MyService(MyDependency myDependency) {
        this.myDependency = myDependency;
    }

    public void doWork() {
        myDependency.doSomething();
    }
}

Spring can inject MyDependency because:

  1. MyDependency is a Spring bean, for example annotated with @Component.
  2. MyService is also a Spring bean, for example annotated with @Service.
  3. MyService has a constructor that requires MyDependency.

In modern Spring, if the class has only one constructor, you usually do not need @Autowired:

@Service
public class MyService {

    private final MyDependency myDependency;

    public MyService(MyDependency myDependency) {
        this.myDependency = myDependency;
    }
}

If you use Lombok, you can make it shorter:

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class MyService {

    private final MyDependency myDependency;

    public void doWork() {
        myDependency.doSomething();
    }
}

Constructor injection is recommended because it makes dependencies explicit, allows fields to be final, improves testability, and prevents partially initialized objects.

How do I use @Component, @Service, and @Repository correctly?

Short Answer

Use these annotations according to the role of the class:

Annotation Use for Typical layer
@Component Generic Spring-managed class Utility/infrastructure/helper
@Service Business logic Service layer
@Repository Data access / persistence Repository/DAO layer

All three make the class a Spring bean, meaning Spring can create it, manage it, and inject it into other beans.


1. @Component: Generic Spring Bean

Use @Component when the class should be managed by Spring but does not clearly belong to the service, repository, or controller layer.

import org.springframework.stereotype.Component;

@Component
public class FileNameGenerator {

    public String generate(String originalName) {
        return System.currentTimeMillis() + "-" + originalName;
    }
}

Good uses for @Component:

  • formatters
  • mappers
  • validators
  • helpers
  • schedulers
  • adapters
  • general infrastructure classes

If a class contains business logic, prefer @Service instead.


2. @Service: Business Logic

Use @Service for classes that represent application/business operations.

import org.springframework.stereotype.Service;

@Service
public class EmployeeService {

    private final EmployeeRepository employeeRepository;

    public EmployeeService(EmployeeRepository employeeRepository) {
        this.employeeRepository = employeeRepository;
    }

    public Employee getEmployee(Long id) {
        return employeeRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("Employee not found"));
    }
}

Good uses for @Service:

  • coordinating business workflows
  • applying business rules
  • calling repositories
  • calling external APIs
  • handling transactions

Example:

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class PayrollService {

    private final EmployeeRepository employeeRepository;

    public PayrollService(EmployeeRepository employeeRepository) {
        this.employeeRepository = employeeRepository;
    }

    @Transactional
    public void processPayroll(Long employeeId) {
        Employee employee = employeeRepository.findById(employeeId)
                .orElseThrow(() -> new IllegalArgumentException("Employee not found"));

        // business logic here
    }
}

@Service is technically a specialized @Component, but it communicates intent:
this class contains business/service logic.


3. @Repository: Database/Data Access

Use @Repository for persistence classes: DAOs, database gateways, or repositories.

With Spring Data JPA, you usually define an interface:

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}

For Spring Data JPA interfaces, @Repository is often optional because Spring Data can detect repository interfaces automatically, but adding it is still common and makes the role explicit.

Use @Repository for:

  • JPA repositories
  • JDBC DAOs
  • persistence adapters
  • custom database access classes

Example custom DAO:

import jakarta.persistence.EntityManager;
import org.springframework.stereotype.Repository;

@Repository
public class EmployeeDao {

    private final EntityManager entityManager;

    public EmployeeDao(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    public Employee findById(Long id) {
        return entityManager.find(Employee.class, id);
    }
}

@Repository also has an extra Spring meaning: it can participate in persistence exception translation, where database-specific exceptions are translated into Spring’s data access exception hierarchy.


4. Recommended Layering

A typical Spring MVC + Spring Data JPA flow looks like this:

Controller -> Service -> Repository -> Database

Example:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class EmployeeController {

    private final EmployeeService employeeService;

    public EmployeeController(EmployeeService employeeService) {
        this.employeeService = employeeService;
    }

    @GetMapping("/employees/{id}")
    public Employee getEmployee(@PathVariable Long id) {
        return employeeService.getEmployee(id);
    }
}
import org.springframework.stereotype.Service;

@Service
public class EmployeeService {

    private final EmployeeRepository employeeRepository;

    public EmployeeService(EmployeeRepository employeeRepository) {
        this.employeeRepository = employeeRepository;
    }

    public Employee getEmployee(Long id) {
        return employeeRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("Employee not found"));
    }
}
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}

5. Prefer Constructor Injection

For all of these beans, prefer constructor injection:

import org.springframework.stereotype.Service;

@Service
public class OrderService {

    private final PaymentClient paymentClient;

    public OrderService(PaymentClient paymentClient) {
        this.paymentClient = paymentClient;
    }

    public void placeOrder() {
        paymentClient.charge();
    }
}

Avoid field injection like this:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class OrderService {

    @Autowired
    private PaymentClient paymentClient;
}

Field injection works, but constructor injection is usually better because:

  • dependencies are explicit
  • fields can be final
  • the class is easier to test
  • the object cannot be created without required dependencies

If you use Lombok, this is common:

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class OrderService {

    private final PaymentClient paymentClient;

    public void placeOrder() {
        paymentClient.charge();
    }
}

6. Common Mistakes

Mistake 1: Using @Component for everything

This works:

@Component
public class EmployeeService {
}

But this is clearer:

@Service
public class EmployeeService {
}

Use the most specific annotation when possible.


Mistake 2: Putting business logic in repositories

Avoid this:

@Repository
public class EmployeeRepository {

    public void calculateBonusAndSaveEmployee() {
        // business rules mixed with database access
    }
}

Prefer:

Service: business rules
Repository: database access

Mistake 3: Injecting repositories directly into controllers

This is not always wrong, but for non-trivial applications it usually leads to poor layering.

Less ideal:

@RestController
public class EmployeeController {

    private final EmployeeRepository employeeRepository;

    public EmployeeController(EmployeeRepository employeeRepository) {
        this.employeeRepository = employeeRepository;
    }
}

Better:

@RestController
public class EmployeeController {

    private final EmployeeService employeeService;

    public EmployeeController(EmployeeService employeeService) {
        this.employeeService = employeeService;
    }
}

The service layer gives you a place for validation, transactions, business rules, and orchestration.


7. Component Scanning Matters

Spring only finds these annotations if the classes are inside packages that Spring scans.

In Spring Boot, this usually works automatically if your main class is in the root package:

com.example.app
├── Application.java
├── controller
│   └── EmployeeController.java
├── service
│   └── EmployeeService.java
└── repository
    └── EmployeeRepository.java

If your annotated classes are outside the scanned package, Spring will not create beans for them.


Rule of Thumb

Use this:

@Component   = generic Spring-managed class
@Service     = business logic
@Repository = data access
@Controller / @RestController = web layer

For most applications:

@RestController
public class EmployeeController {
    private final EmployeeService employeeService;
}
@Service
public class EmployeeService {
    private final EmployeeRepository employeeRepository;
}
@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}

That is the standard and correct way to use them.