Skip to main navigation Skip to main content Skip to page footer

Spring Core - Java Configuration

| Java Spring Boot

Define Spring Beans using Java code

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

@Configuration
public class AppConfig {

    @Bean
    public MyService myService() {
        return new MyServiceImpl();
    }

    @Bean
    public MyRepository myRepository() {
        return new MyRepositoryImpl();
    }
}

@Configuration: Marks the class as a configuration source.
@Bean: Indicates that the method produces a bean managed by the Spring container.

Access Beans in the Application Context

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        MyService myService = context.getBean(MyService.class);
        myService.performTask();
    }
}

Handle multiple Configuration files

Using @Import Annotation

You can import multiple configuration classes into a primary configuration class using the @Import annotation.

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import({DataSourceConfig.class, ServiceConfig.class})
public class AppConfig {
    // This class serves as the main configuration file
}

Using AnnotationConfigApplicationContext

You can directly register multiple configuration classes when creating the application context.

Organizing Configurations by Profiles

@Configuration
@Profile("dev")
public class DevConfig {
    @Bean
    public DataSource devDataSource() {
        // Configure dev DataSource
        return new DataSource();
    }
}

XML + Java Configuration

Importing Java into XML
<beans>
    <import resource="com/example/config/AppConfig.class" />
</beans>
Importing XML into Java
@Configuration
@ImportResource("classpath:applicationContext.xml")
public class AppConfig {
}

Handle Dependencies between Beans

Constructor Injection

The dependent bean is passed as a parameter to the constructor of the primary bean.

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

@Configuration
public class AppConfig {

    @Bean
    public ServiceA serviceA() {
        return new ServiceA(serviceB());
    }

    @Bean
    public ServiceB serviceB() {
        return new ServiceB();
    }
}
// ServiceA depends on ServiceB
public class ServiceA {
    private final ServiceB serviceB;

    public ServiceA(ServiceB serviceB) {
        this.serviceB = serviceB;
    }

    public void performTask() {
        serviceB.assistTask();
    }
}
public class ServiceB {
    public void assistTask() {
        System.out.println("Task Assisted!");
    }
}

When Spring creates ServiceA, it automatically injects ServiceB.

Setter Injection

Dependencies are injected via setter methods.

@Configuration
public class AppConfig {

    @Bean
    public ServiceA serviceA() {
        ServiceA serviceA = new ServiceA();
        serviceA.setServiceB(serviceB());
        return serviceA;
    }

    @Bean
    public ServiceB serviceB() {
        return new ServiceB();
    }
}
// ServiceA with Setter

@Service
public class ServiceA {
    private ServiceB serviceB;

    public void setServiceB(ServiceB serviceB) {
        this.serviceB = serviceB;
    }

    public void performTask() {
        serviceB.assistTask();
    }
}

Field Injection (with @Autowired)

Spring can directly inject dependencies into fields using the @Autowired annotation.

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

@Component
public class ServiceA {
    @Autowired
    private ServiceB serviceB;

    public void performTask() {
        serviceB.assistTask();
    }
}

@Component
public class ServiceB {
    public void assistTask() {
        System.out.println("Task Assisted!");
    }
}

With component scanning enabled, Spring automatically injects ServiceB into ServiceA:

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

@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
}

Using @DependsOn

If one bean must be initialized before another, use the @DependsOn annotation. This ensures ServiceB is initialized before ServiceA.

@Configuration
public class AppConfig {

    @Bean
    @DependsOn("serviceB")
    public ServiceA serviceA() {
        return new ServiceA();
    }

    @Bean
    public ServiceB serviceB() {
        return new ServiceB();
    }
}

Circular Dependencies

If two beans depend on each other, Spring resolves it by using proxies or lazily initialized beans.

@Configuration
public class AppConfig {

    @Bean
    public BeanA beanA() {
        return new BeanA(beanB());
    }

    @Bean
    public BeanB beanB() {
        return new BeanB();
    }
}

If circular dependencies occur, use @Lazy to break the initialization loop:

public class BeanA {
    private final BeanB beanB;

    public BeanA(@Lazy BeanB beanB) {
        this.beanB = beanB;
    }
}

Best Practices

  • Use constructor injection for mandatory dependencies (recommended for immutability).
  • Use setter injection for optional dependencies.
  • Avoid circular dependencies by reviewing bean design.
  • Use @Lazy or @DependsOn only when necessary to manage initialization order.

Spring's IoC container ensures dependencies are managed efficiently, making it easy to handle relationships between beans.

Explain and define Bean Scopes

@Configuration
public class AppConfig {
    @Bean
    @Scope("singleton")
    public MyBean myBean() {
        return new MyBean();
    }
}

Scopes

Singleton

Definition: A single instance of the bean is created and shared across the entire Spring container.

Prototype

Definition: A new instance of the bean is created every time it is requested.

Request

Definition: A new instance of the bean is created for each HTTP request and is valid only within the lifecycle of the request.

Session

Definition: A single instance of the bean is created and associated with an HTTP session. It is valid until the session is terminated.

Application

Definition: A single instance of the bean is shared across the entire application and remains valid for the entire lifecycle of the ServletContext.

WebSocket

Definition: A single instance of the bean is created and tied to the lifecycle of a WebSocket.

Choosing the Right Scope

  • Use singleton for stateless, reusable components.
  • Use prototype for stateful or per-user/request components.
  • Use request or session for web-specific scenarios.
  • Use application for global data shared across the application.
  • Use websocket for WebSocket-based interactions.
Back