In the dynamic world of Spring applications, managing which beans are active at runtime, how they are named, and how to precisely inject them is crucial. Spring offers a suite of conditional annotations, naming conventions, and injection mechanisms to achieve this flexibility. Let’s delve into them:

Naming Beans

  • Default Naming: By default, Spring uses the following strategies to name beans:

    • @Component, @Service, @Repository, @Controller: The class name with the first letter lowercase (e.g., myService for MyService).
    • @Bean: The method name (e.g., dataSource for @Bean public DataSource dataSource() { ... }).
  • Custom Naming:

    • @Component, @Service, etc.: Provide a value within the annotation (e.g., @Service("myCustomService")).
    • @Bean: Use the name attribute (e.g., @Bean(name = "myCustomBean")).

Specifying Beans by Name in Injection

When you have multiple beans of the same type, you need a way to tell Spring which one to inject. Here are the primary methods:

  1. @Qualifier

    • The most common and recommended approach.
    • Use it with @Autowired or @Inject.
    • Example:
    @Autowired
    @Qualifier("myCustomBean")
    private MyBean myBean;
    
  2. @Resource

    • Offers similar functionality to @Qualifier but is part of the Java EE standard, not Spring-specific.
    • Can also match by type if no name is provided.
    • Example:
    @Resource(name = "myCustomBean")
    private MyBean myBean;
    

Conditional Bean Creation

Conditional Bean Creation

1. @ConditionalOnProperty

  • Use Case: Controls bean creation based on specific property values or the existence of a property.
  • Example:
@Configuration
@ConditionalOnProperty(name = "feature.enabled", havingValue = "true")
@Primary // This bean will be the primary choice if multiple beans of the same type exist
public class FeatureBean { ... }
  • Explanation: FeatureBean is only created if the property “feature.enabled” exists and has the value “true”. If multiple beans of the same type are created, FeatureBean will be the primary choice due to the @Primary annotation.

2. @ConditionalOnClass and @ConditionalOnMissingClass

  • Use Case: Ideal for handling optional dependencies. A bean is created only if a specific class is present (or missing) in the classpath.
  • Example:
@Configuration
@ConditionalOnClass(name = "com.example.OptionalDependency")
@Primary 
public class DependentBean { ... }
  • Explanation: DependentBean is only created if the class “com.example.OptionalDependency” is available. If multiple beans of the same type are created, DependentBean will be the primary choice.

3. @ConditionalOnBean and @ConditionalOnMissingBean

  • Use Case: Enables you to create beans based on the presence (or absence) of other beans within the Spring context.
  • Example:
@Configuration
@ConditionalOnBean(DataSource.class)
@Primary
public class DatabaseBean { ... }
  • Explanation: DatabaseBean is only created if a bean of type DataSource already exists in the context. If multiple beans of the same type are created, DatabaseBean will be the primary choice.

4. @Profile

  • Use Case: While not strictly a conditional annotation, @Profile allows you to activate beans based on active Spring profiles.
  • Example:
@Configuration
@Profile("development")
@Primary
public class DevBean { ... }
  • Explanation: DevBean is only created when the “development” profile is active. If multiple beans of the same type are created, DevBean will be the primary choice.

The Role of @Primary

In Spring, it’s possible to have multiple beans of the same type within your application context. This can occur intentionally (e.g., providing different implementations for different scenarios) or unintentionally (e.g., third-party libraries contributing beans). When autowiring or injecting beans by type, Spring needs a way to determine which bean to use if there are multiple candidates.

This is where @Primary comes in. When you annotate a bean with @Primary, you’re essentially marking it as the preferred choice if there are multiple beans of the same type available. Spring will prioritize injecting the @Primary bean unless you explicitly specify a different bean using @Qualifier or @Resource.

Example:

@Configuration
@Primary
public class DefaultEmailService implements EmailService { ... }

@Configuration
public class BackupEmailService implements EmailService { ... }

@Service
public class MyService {

    @Autowired
    private EmailService emailService; // This will inject DefaultEmailService

    // ...
}

In this example, both DefaultEmailService and BackupEmailService implement the EmailService interface. Since DefaultEmailService is marked with @Primary, it will be the one injected into MyService by default.

Important Considerations:

  • @Primary only influences bean selection when there are multiple beans of the same type. It doesn’t affect the creation or existence of the bean itself.
  • You can combine @Primary with conditional annotations to create scenarios where a bean is only primary under certain conditions.
  • If you have multiple @Primary beans of the same type, Spring will throw an exception during startup, indicating an ambiguous situation.
  • Combining Annotations: Combine multiple conditional annotations for fine-grained control.
  • Custom Conditions: Create custom conditions by implementing the Condition interface.

Spring’s conditional annotations, naming conventions, injection mechanisms (@Qualifier, @Resource), and the @Primary annotation provide a powerful toolkit for creating dynamic and adaptable applications. By mastering these tools, you gain precise control over your bean configuration, injection, and selection, allowing you to tailor your application to various environments and runtime conditions.


Discover more from GhostProgrammer - Jeff Miller

Subscribe to get the latest posts sent to your email.

By Jeffery Miller

I am known for being able to quickly decipher difficult problems to assist development teams in producing a solution. I have been called upon to be the Team Lead for multiple large-scale projects. I have a keen interest in learning new technologies, always ready for a new challenge.