Spring Core Interview Questions and Answers (2026)
-
Last Updated: April 27, 2026
-
By: javahandson
-
Series
Learn Java in a easy way
Looking for Spring Core interview questions? This guide covers 15 in-depth Spring Core interview questions and answers on IoC, Dependency Injection types, ApplicationContext vs BeanFactory, @Component vs @Bean, Component Scanning internals, @Qualifier vs @Primary, Circular Dependency and @Profile — each with working code examples and interview insights for 2026.
Answer – The Spring Framework is an open-source, lightweight application framework for the Java platform. It was created by Rod Johnson and first released in 2003 as a response to the excessive complexity of J2EE (Java 2 Enterprise Edition) development at the time. The central promise of Spring is simple: let developers focus on business logic and delegate all infrastructure concerns — object creation, wiring, lifecycle management, transaction handling, security, and more — to the framework itself.
At its heart, Spring provides two foundational capabilities. First, it implements the Inversion of Control (IoC) principle through a container that manages object creation and their dependencies. Second, it uses Dependency Injection (DI) as the mechanism to supply those dependencies. These two concepts, which are explained in depth in subsequent questions, form the backbone of everything Spring does.
Why developers and companies use Spring
Spring is not used simply because it is popular. It solves real, recurring problems in enterprise Java development:
A quick analogy
Think of Spring as a factory manager. Without Spring, every class is responsible for creating its own tools (dependencies). With Spring, the factory manager (the IoC container) creates all the tools, organises them, and hands each worker exactly what they need. The worker just focuses on the job.
Answer – Inversion of Control (IoC) is a design principle, not a Spring-specific feature. The term describes the inversion of the flow of control in a program. In traditional programming, your application code calls a library to perform tasks — the application is in control. IoC reverses this: a framework or container takes control and calls your code at the right time.
In the context of object-oriented design, IoC specifically refers to inverting who is responsible for creating and managing an object’s dependencies. Without IoC, a class creates its own dependencies internally. With IoC, those dependencies are provided externally by a container or framework.
Without IoC — tight coupling
public class OrderService {
// OrderService creates its own dependency — tightly coupled
private PaymentService paymentService = new PaymentService();
public void placeOrder(Order order) {
paymentService.charge(order.getAmount());
}
}
The problem here is clear. OrderService directly creates a PaymentService. If you want to use a different payment strategy in tests (say, a mock), you cannot — the concrete class is hardcoded inside the constructor.
With IoC — loose coupling
public class OrderService {
// The dependency is provided externally — not created here
private final PaymentService paymentService;
public OrderService(PaymentService paymentService) {
this.paymentService = paymentService;
}
public void placeOrder(Order order) {
paymentService.charge(order.getAmount());
}
}
Now OrderService does not know or care whether PaymentService is a real implementation or a mock. The caller — in a Spring application, the IoC container — decides what to inject. This is IoC in action.
The IoC Container in Spring
Spring implements IoC through its container. The container reads your configuration (annotations, XML, or Java config), creates all the objects (called beans) your application needs, injects their dependencies, and manages their lifecycle. You describe what you need; Spring figures out how to wire everything together.
Answer – Dependency Injection is the concrete mechanism Spring uses to implement IoC. The idea is straightforward: instead of a class creating the objects it depends on, those objects (dependencies) are injected into it from the outside. Spring’s IoC container is responsible for performing that injection at application startup.
The term ‘injection’ simply means the container passes the dependency into the class — either through the constructor, a setter method, or directly into a field. The class itself has no knowledge of how the dependency was created, where it came from, or what its lifecycle is. This separation of concerns is the core benefit of DI.
How DI works in Spring — a minimal example
@Service
public class UserService {
private final UserRepository userRepository;
// Spring injects UserRepository here via constructor injection
// Autowired is optional in modern Spring when there is only one constructor
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User findById(Long id) {
return userRepository.findById(id).orElseThrow();
}
}
When Spring starts up, it scans for @Service, @Repository, and other stereotype annotations. It finds UserRepository, creates an instance of it, then creates an instance of UserService and passes that UserRepository instance into its constructor. The developer never writes ‘new UserRepository()’ anywhere.
Benefits of DI
Answer – Spring supports three mechanisms for injecting dependencies into a bean. Each has a different syntax, a different behaviour, and a different set of trade-offs.
1. Constructor Injection
The dependency is provided through the class constructor. This is the most recommended approach.
@Service
public class OrderService {
private final PaymentService paymentService;
private final InventoryService inventoryService;
// Spring calls this constructor and injects both dependencies
public OrderService(PaymentService paymentService,
InventoryService inventoryService) {
this.paymentService = paymentService;
this.inventoryService = inventoryService;
}
}
Notice the fields are final. Once injected, they cannot be changed. This guarantees the object is fully initialised before any method is called.
2. Setter Injection
The dependency is provided through a public setter method after the bean is instantiated.
@Service
public class ReportService {
private EmailService emailService;
@Autowired
public void setEmailService(EmailService emailService) {
this.emailService = emailService;
}
}
Setter injection is useful when the dependency is optional or when you need to reconfigure the bean after creation (for example, in certain testing scenarios).
3. Field Injection
The dependency is injected directly into the field via reflection, without a constructor or setter.
@Service
public class NotificationService {
@Autowired
private SmsService smsService; // Spring injects this via reflection
public void notify(String message) {
smsService.send(message);
}
}
Field injection is the most concise syntax, which is why many developers use it. However, it comes with significant drawbacks that are discussed in Question 5.
| Feature | Constructor | Setter | Field |
| Fields can be final | Yes | No | No |
| Null safety at startup | Yes (fails fast) | No | No |
| Circular dep detection | Immediate exception | Allowed* | Allowed* |
| Testability without Spring | Easy — just call constructor | Moderate | Hard — needs reflection |
| Spring team recommendation | Preferred | Optional deps only | Discouraged |
Answer – The Spring team officially recommends constructor injection as the primary injection style, and this recommendation has been consistent since Spring 4. The reasons are concrete, not just stylistic.
Why Constructor Injection is recommended
1. Immutability: Constructor-injected fields can be declared final. This means once the object is built, its dependencies cannot be accidentally changed or set to null by another part of the code.
2. Fail-fast at startup: If a required dependency is missing, Spring throws an exception immediately when the application starts, not later when a method is called. This surfaces configuration problems early and makes debugging straightforward.
3. Testability without the container: You can instantiate the class directly in a unit test by simply calling new MyService(mockRepository). No Spring context needed. With field injection, you must either use Spring’s test support or reflection to inject mocks.
4. Clear contract: The constructor signature explicitly declares every dependency a class needs. When a class has too many constructor parameters, it is a visible code smell that the class has too many responsibilities — a useful design warning.
Why Field Injection is discouraged
Despite being the most common syntax found in tutorials, field injection has real problems in production code:
When Setter Injection is appropriate
Setter injection is reasonable for optional dependencies — those that have a sensible default and where the absence of the dependency should not cause the bean to fail. You can combine it with @Autowired(required = false) to make a dependency truly optional.
@Service
public class AuditService {
// This works fine without a MetricsClient
private MetricsClient metricsClient;
@Autowired(required = false)
public void setMetricsClient(MetricsClient metricsClient) {
this.metricsClient = metricsClient;
}
}
Answer – @Autowired is Spring’s annotation for triggering automatic dependency injection. When Spring’s container encounters a constructor, setter method, or field annotated with @Autowired, it resolves the appropriate bean and injects it. Understanding how Spring resolves the injection is more important than knowing the annotation’s syntax.
How Spring resolves @Autowired — step by step
Example — ambiguity resolved with @Qualifier
@Component
public class GmailNotifier implements NotificationService { ... }
@Component
public class SlackNotifier implements NotificationService { ... }
@Service
public class AlertService {
private final NotificationService notificationService;
// Without @Qualifier, Spring would throw NoUniqueBeanDefinitionException
public AlertService(
@Qualifier("slackNotifier") NotificationService notificationService) {
this.notificationService = notificationService;
}
}
The internal mechanism — AutowiredAnnotationBeanPostProcessor
Internally, Spring uses a BeanPostProcessor called AutowiredAnnotationBeanPostProcessor to process @Autowired annotations. This processor runs after the bean is instantiated but before it is put into service. It reflects over the class, finds annotated fields and methods, resolves the correct beans using the algorithm above, and injects them.
For constructor injection, Spring does not need @Autowired at all when there is only one constructor — the container automatically uses the single available constructor. @Autowired becomes necessary only when multiple constructors exist and you need to indicate which one Spring should use.
// @Autowired is optional when there is exactly one constructor
@Service
public class ProductService {
private final ProductRepository productRepository;
// Spring uses this automatically — no @Autowired needed (Spring 4.3+)
public ProductService(ProductRepository productRepository) {
this.productRepository = productRepository;
}
}
Answer – ApplicationContext is Spring’s central interface for the IoC container. It extends BeanFactory (discussed in the next question) and adds a rich set of enterprise features on top of basic bean management. When a Spring application starts, the ApplicationContext reads your configuration, instantiates all singleton beans eagerly, wires their dependencies, and keeps them ready to serve requests.
Every Spring application — whether it is a standalone Java program, a web application, or a Spring Boot microservice — has exactly one ApplicationContext (or occasionally a hierarchy of them in advanced scenarios). It is the beating heart of the application.
What ApplicationContext provides
Main Implementations
Spring provides several concrete implementations of ApplicationContext, each suited to a different configuration style or environment:
AnnotationConfigApplicationContext
Used in standalone applications (non-web) where configuration is provided via Java @Configuration classes or @Component-scanned packages.
@Configuration
@ComponentScan("com.example")
public class AppConfig { }
// Bootstrapping the context manually in a main method
public class MainApp {
public static void main(String[] args) {
ApplicationContext ctx =
new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = ctx.getBean(UserService.class);
userService.doSomething();
}
}
ClassPathXmlApplicationContext
The original XML-based context. Loads bean definitions from an XML file on the classpath. Still encountered in legacy enterprise applications.
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
GenericWebApplicationContext / AnnotationConfigWebApplicationContext
Used in web applications. These implementations are aware of the Servlet API and integrate with the DispatcherServlet. In modern Spring Boot applications, you rarely create these manually — Spring Boot auto-configures them.
In Spring Boot
In a Spring Boot application you almost never instantiate ApplicationContext yourself. Spring Boot creates it internally and makes it available via the SpringApplication.run() return value if you need it.
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
// Spring Boot creates and manages the ApplicationContext
ApplicationContext ctx = SpringApplication.run(MyApplication.class, args);
// You can retrieve beans if needed
UserService svc = ctx.getBean(UserService.class);
}
}
Answer – BeanFactory is the root interface for Spring’s IoC container. It provides the basic contract for managing beans: primarily getBean() to retrieve a bean by name or type. ApplicationContext extends BeanFactory and adds a significant layer of enterprise features on top of it.
In modern Spring development, you will almost never use a BeanFactory directly. It exists as a foundational abstraction that other containers build upon. The practical distinction matters primarily for understanding when each is appropriate and for answering interview questions that probe your knowledge of the container hierarchy.
| Feature | BeanFactory | ApplicationContext |
| Bean initialisation | Lazy — on first getBean() call | Eager — at container startup |
| Annotation processing | Not automatic | Automatic (BeanPostProcessors) |
| @Autowired support | Not built-in | Built-in |
| Event publishing | Not supported | Supported via ApplicationEvent |
| i18n / MessageSource | Not supported | Supported |
| Environment / Profiles | Not supported | Supported |
| AOP auto-proxy | Not automatic | Automatic |
| Resource loading | Basic | Rich ResourceLoader support |
| Use in production | Rarely — resource-constrained envs | Almost always |
When would you ever use BeanFactory?
BeanFactory’s lazy initialisation means beans are only created when first requested. This is useful in resource-constrained environments (embedded devices, for example) where you need to minimise startup memory usage. In practice, even Spring Boot applications for IoT devices use ApplicationContext — the lazy loading benefit rarely outweighs the lost features.
// Using DefaultListableBeanFactory directly (very rare in practice)
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(new ClassPathResource("beans.xml"));
// Bean is NOT created yet — BeanFactory is lazy
MyService service = factory.getBean(MyService.class); // created here
// Using ApplicationContext — all singletons already created at this point
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
MyService service2 = ctx.getBean(MyService.class); // already exists
Answer – These three annotations all result in Spring-managed beans, but they serve different purposes and apply in different contexts. Confusing them is one of the most common mistakes in Spring code.
@Component — for your own classes
@Component is a class-level annotation that marks a class as a Spring-managed bean. Spring detects it during component scanning and creates an instance automatically. You use @Component (and its specialisations @Service, @Repository, @Controller) on classes that you own — classes in your codebase.
@Component // Spring will create and manage this bean
public class EmailValidator {
public boolean isValid(String email) {
return email != null && email.contains("@");
}
}
@Service, @Repository, and @Controller are specialisations of @Component. They add semantic meaning (service layer, data layer, web layer) and some Spring behaviour — @Repository, for example, enables Spring’s exception translation for database errors.
@Bean — for third-party or programmatic beans
@Bean is a method-level annotation used inside a @Configuration class. You use it when you need to register a bean that you cannot annotate directly with @Component — typically because it is a class from a third-party library, or because its creation requires specific configuration logic.
@Configuration
public class AppConfig {
// You cannot annotate ObjectMapper with @Component
// because it's a Jackson library class
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return mapper;
}
// Custom DataSource with specific pool settings
@Bean
public DataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:postgresql://localhost/mydb");
config.setMaximumPoolSize(20);
return new HikariDataSource(config);
}
}
@Configuration — for configuration classes
@Configuration marks a class as a source of bean definitions. It tells Spring that this class contains @Bean methods that should be processed. Without @Configuration, a class with @Bean methods still works, but with an important behavioural difference.
@Configuration // CGLIB-proxied — inter-bean method calls are intercepted
public class DatabaseConfig {
@Bean
public DataSource dataSource() { ... }
@Bean
public EntityManagerFactory entityManagerFactory() {
// Calling dataSource() here returns the SAME Spring bean
// because @Configuration enables CGLIB proxy
return new LocalContainerEntityManagerFactoryBean(dataSource());
}
}
Without @Configuration (using @Component instead), the dataSource() call inside entityManagerFactory() would create a brand new DataSource each time — not the Spring-managed singleton.
| Annotation | Applied to | Use when | Component scan? |
| @Component | Class | Your own class that should be a bean | Yes |
| @Bean | Method | Third-party class or complex construction logic | No — inside @Configuration |
| @Configuration | Class | Declaring multiple @Bean methods as a unit | Yes |
Answer – Component scanning is the mechanism by which Spring automatically discovers and registers beans from your classpath, without you having to declare each one manually in a configuration file. When component scanning is enabled, Spring scans the packages you specify, finds all classes annotated with @Component (or its specialisations), and registers them as bean definitions in the container.
How to enable component scanning
// Option 1: Java configuration
@Configuration
@ComponentScan(basePackages = "com.example.myapp")
public class AppConfig { }
// Option 2: Spring Boot — @SpringBootApplication includes @ComponentScan
// It scans the package of the annotated class and all sub-packages
@SpringBootApplication // includes @ComponentScan
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
How it works internally — step by step
Filtering component scanning
You can include or exclude specific classes or annotations from scanning:
@ComponentScan(
basePackages = "com.example",
excludeFilters = @ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = Repository.class // exclude all @Repository beans
),
includeFilters = @ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = SpecialService.class
)
)
public class AppConfig { }
Answer – Both @Qualifier and @Primary exist to resolve the same problem: when Spring finds multiple beans of the same type, it cannot decide which one to inject and throws a NoUniqueBeanDefinitionException. These two annotations provide different ways to resolve that ambiguity.
@Primary — the default choice
@Primary marks one bean as the default candidate when multiple beans of the same type are available. You use @Primary when one implementation should be the standard choice and the others are exceptions or alternatives.
public interface PaymentGateway {
void process(double amount);
}
@Component
@Primary // This is the default choice when PaymentGateway is injected
public class StripeGateway implements PaymentGateway { ... }
@Component
public class PayPalGateway implements PaymentGateway { ... }
@Service
public class CheckoutService {
private final PaymentGateway paymentGateway;
// Spring injects StripeGateway because it is @Primary
public CheckoutService(PaymentGateway paymentGateway) {
this.paymentGateway = paymentGateway;
}
}
@Qualifier — explicit selection
@Qualifier allows you to specify exactly which bean you want by its name or qualifier value. You use @Qualifier at the injection point to override the default resolution. This is more explicit and more granular than @Primary.
@Service
public class RefundService {
private final PaymentGateway stripeGateway;
private final PaymentGateway payPalGateway;
public RefundService(
@Qualifier("stripeGateway") PaymentGateway stripeGateway,
@Qualifier("payPalGateway") PaymentGateway payPalGateway) {
this.stripeGateway = stripeGateway;
this.payPalGateway = payPalGateway;
}
}
How they interact
If both @Primary and @Qualifier are involved: @Qualifier always wins. If the injection point has a @Qualifier, Spring uses it, regardless of whether one of the candidates is @Primary.
| Aspect | @Primary | @Qualifier |
| Where to place | On the bean definition | At the injection point |
| Granularity | Application-wide default | Per-injection-point control |
| Best for | One obvious default choice | Injecting specific implementations |
| When both present | Overridden by @Qualifier | Takes priority |
Answer
A circular dependency occurs when two or more beans depend on each other, forming a cycle. For example: Bean A requires Bean B, and Bean B requires Bean A. When Spring tries to create A, it starts creating B, which needs A — but A is not finished yet. This creates a deadlock in the instantiation process.
Example of a circular dependency
@Service
public class ServiceA {
private final ServiceB serviceB;
public ServiceA(ServiceB serviceB) { // A depends on B
this.serviceB = serviceB;
}
}
@Service
public class ServiceB {
private final ServiceA serviceA;
public ServiceB(ServiceA serviceA) { // B depends on A — circular!
this.serviceA = serviceA;
}
}
How Spring detects and handles circular dependencies
The behaviour depends on the type of injection being used:
// This will FAIL at startup with constructor injection: // BeanCurrentlyInCreationException: Error creating bean 'serviceA': // Requested bean is currently in creation: Is there an unresolvable circular reference? // Spring Boot 2.6+ also detects setter/field circular deps by default // and throws an exception instead of silently allowing them. // You can re-enable the old behaviour with: // spring.main.allow-circular-references=true (not recommended)
The right fix: refactor the design
A circular dependency is almost always a sign of a design problem — two classes are too tightly coupled to each other. The solutions include:
// Using @Lazy to break a circular dependency (use sparingly)
@Service
public class ServiceA {
private final ServiceB serviceB;
public ServiceA(@Lazy ServiceB serviceB) {
this.serviceB = serviceB;
}
}
Answer – By default, Spring creates all singleton beans eagerly at application startup. @Lazy is an annotation that changes this behaviour for a specific bean — it tells Spring to defer the creation of that bean until the first time it is requested (via getBean() or through injection).
Usage on a bean definition
@Component
@Lazy // This bean will NOT be created at startup
public class HeavyReportGenerator {
public HeavyReportGenerator() {
// Imagine this takes 5 seconds and allocates significant memory
System.out.println("HeavyReportGenerator initialised");
}
}
If no code ever requests this bean during the application’s lifetime, it is never created. This can improve startup time for applications with beans that are rarely or never used.
Usage at the injection point
You can also apply @Lazy at the injection point, which injects a CGLIB proxy instead of the actual bean. The real bean is created only when a method is first called on that proxy.
@Service
public class DashboardService {
// A proxy is injected at startup.
// The real HeavyReportGenerator is created only on first method call.
@Autowired
@Lazy
private HeavyReportGenerator reportGenerator;
public void generateReport() {
// HeavyReportGenerator is instantiated HERE, on first use
reportGenerator.generate();
}
}
When to use @Lazy
Caution with @Lazy
Overusing @Lazy can hide startup problems. If a bean fails to initialise (e.g., because its configuration is wrong), you will discover that error the first time a user triggers that code path — not at startup when you can catch it immediately. Use @Lazy deliberately, not as a default.
Answer – Spring has supported three distinct styles of configuration throughout its evolution. Each was the preferred approach in its era, and each still works in modern Spring — though Java-based configuration is now the standard in new projects.
XML-based configuration (Spring 1.x era)
The original Spring approach. All bean definitions are declared in an XML file. Verbose and explicit, but very clear about what is being configured.
<!-- applicationContext.xml -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="...">
<bean id="userRepository" class="com.example.UserRepositoryImpl"/>
<bean id="userService" class="com.example.UserService">
<constructor-arg ref="userRepository"/>
</bean>
</beans>
Annotation-based configuration (Spring 2.5+)
Spring 2.5 introduced @Component, @Autowired, and @Service, allowing bean definitions and injection to be declared directly in the Java source code. XML was still needed to enable component scanning.
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
}
// Still needed some XML or Java config to enable scanning:
// <context:component-scan base-package="com.example"/>
Java-based configuration (Spring 3.0+)
@Configuration and @Bean eliminated the need for XML entirely. Configuration is expressed as plain Java code, which is type-safe, refactorable, and IDE-friendly.
@Configuration
@ComponentScan("com.example")
@PropertySource("classpath:application.properties")
public class AppConfig {
@Bean
public DataSource dataSource(
@Value("${db.url}") String url,
@Value("${db.username}") String username) {
HikariConfig cfg = new HikariConfig();
cfg.setJdbcUrl(url);
cfg.setUsername(username);
return new HikariDataSource(cfg);
}
}
| Aspect | XML | Annotation | Java Config |
| Type safety | None | Partial | Full |
| Refactoring support | None (strings) | Good | Excellent |
| Verbosity | High | Low | Medium |
| Visibility of wiring | Centralised in XML | Scattered in classes | Centralised in @Config |
| Third-party beans | Yes (in XML) | No | Yes (via @Bean) |
| Modern Spring Boot | Not preferred | Yes (@Component etc.) | Preferred for config |
In practice, modern Spring Boot applications use a combination: @Component and its specialisations for application classes, @Configuration + @Bean for infrastructure beans (DataSource, RestTemplate, etc.), and application.properties / application.yml for externalised values.
Answer – @Profile is Spring’s mechanism for environment-based conditional bean registration. It allows you to define beans that should only be active in certain environments — for example, a bean that connects to a real database in production but uses an in-memory database in development, or a mock email service in tests.
A profile is simply a named grouping. You assign beans to profiles, and then at application startup you tell Spring which profile(s) are active. Spring only registers beans that belong to the active profile (or no profile at all — unprofile beans are always registered).
Defining beans with @Profile
// Only active in 'production' environment
@Configuration
@Profile("production")
public class ProductionDataSourceConfig {
@Bean
public DataSource dataSource() {
// Connect to real PostgreSQL database
HikariConfig cfg = new HikariConfig();
cfg.setJdbcUrl("jdbc:postgresql://prod-db:5432/appdb");
return new HikariDataSource(cfg);
}
}
// Only active in 'development' or 'test' environment
@Configuration
@Profile({"development", "test"})
public class DevDataSourceConfig {
@Bean
public DataSource dataSource() {
// In-memory H2 database — no external dependency
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.build();
}
}
Activating profiles
Profiles can be activated in several ways:
# Option 1: application.properties or application.yml
spring.profiles.active=production
# Option 2: Environment variable (useful in Docker/Kubernetes)
SPRING_PROFILES_ACTIVE=production
# Option 3: JVM system property
# java -Dspring.profiles.active=production -jar myapp.jar
# Option 4: Programmatic (useful in tests)
// @ActiveProfiles("test") on your test class
Profile negation and default profile
// Active in every profile EXCEPT 'production'
@Component
@Profile("!production")
public class MockEmailService implements EmailService { ... }
// Active when no specific profile is activated
@Component
@Profile("default")
public class LocalDevelopmentSetup { ... }
Combining @Profile with @Bean
@Profile can also be applied directly to individual @Bean methods inside a @Configuration class:
@Configuration
public class MessagingConfig {
@Bean
@Profile("production")
public MessageBroker kafkaBroker() {
return new KafkaMessageBroker("kafka:9092");
}
@Bean
@Profile("!production")
public MessageBroker inMemoryBroker() {
return new InMemoryMessageBroker();
}
}