DEV Community

Hunor Vadasz-Perhat
Hunor Vadasz-Perhat

Posted on

spring-002: setBeanName()-of-BeanNameAware-BeanFactory

Here’s the detailed explanation of the execution flow with the actual code from a simple Java program to demonstrate BeanNameAware's setBeanName() lifecycle interface method.
Buckle up! It will be a long ride 🎢


1. Execution Starts in main()

  • The program begins execution in the main() method. The Spring context is initialized using the AnnotationConfigApplicationContext class with TenantConfig.class as its configuration.

Code:

   public static void main(String[] args) {
       // Initialize Spring context
       AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TenantConfig.class);
       TenantService tenantService = context.getBean(TenantService.class);
       // Process tenant data
       tenantService.processTenantData();
   }
Enter fullscreen mode Exit fullscreen mode

2. Spring Context Initialization

  • The AnnotationConfigApplicationContext processes the TenantConfig class annotated with @Configuration. It scans the package "org.example4" for components like @Service and other Spring-managed beans.

Code:

   @Configuration
   @ComponentScan(basePackages = "org.example4") // Adjust to your package structure
   public class TenantConfig {

       @Bean(name = "tenantA-dataSource")
       public TenantDataSource tenantADataSource() {
           return new TenantDataSource();
       }

       @Bean(name = "tenantB-dataSource")
       public TenantDataSource tenantBDataSource() {
           return new TenantDataSource();
       }
   }
Enter fullscreen mode Exit fullscreen mode

3. Bean Creation in TenantConfig

  • Spring invokes the two @Bean methods (tenantADataSource() and tenantBDataSource()) to create two beans of type TenantDataSource:
    • "tenantA-dataSource"
    • "tenantB-dataSource"

Code for @Bean definitions:

   @Bean(name = "tenantA-dataSource")
   public TenantDataSource tenantADataSource() {
       return new TenantDataSource();
   }

   @Bean(name = "tenantB-dataSource")
   public TenantDataSource tenantBDataSource() {
       return new TenantDataSource();
   }
Enter fullscreen mode Exit fullscreen mode

4. TenantDataSource Bean Initialization

  • The TenantDataSource class implements BeanNameAware, allowing the Spring container to call the setBeanName(String beanName) method during bean initialization.
  • The setBeanName method extracts the tenant name (tenantA or tenantB) from the bean name and assigns a corresponding database URL.

Code:

   public class TenantDataSource implements BeanNameAware {

       private String tenantName;
       private String databaseUrl;

       @Override
       public void setBeanName(String beanName) {
           // Extract tenant name from the bean name
           if (beanName.contains("-")) {
               this.tenantName = beanName.split("-")[0];
           } else {
               throw new IllegalArgumentException("Invalid bean naming convention. Expected format: <tenantName>-dataSource");
           }

           // Assign a database URL dynamically based on the tenant name
           this.databaseUrl = "jdbc:mysql://localhost:3306/" + tenantName + "_db";
       }

       public void connect() {
           System.out.println("Connecting to database for tenant: " + tenantName);
           System.out.println("Using database URL: " + databaseUrl);
           // Simulate connection logic here
       }
   }
Enter fullscreen mode Exit fullscreen mode

5. TenantService Bean Creation

  • Spring scans the package "org.example4" and finds the TenantService class annotated with @Service.
  • The TenantService constructor has dependencies annotated with @Qualifier, which specifies which TenantDataSource beans to inject:
    • "tenantA-dataSource"
    • "tenantB-dataSource"

Code:

   @Service
   public class TenantService {

       private final TenantDataSource tenantADataSource;
       private final TenantDataSource tenantBDataSource;

       @Autowired
       public TenantService(
               @Qualifier("tenantA-dataSource") TenantDataSource tenantADataSource,
               @Qualifier("tenantB-dataSource") TenantDataSource tenantBDataSource
       ) {
           this.tenantADataSource = tenantADataSource;
           this.tenantBDataSource = tenantBDataSource;
       }

       public void processTenantData() {
           System.out.println("Processing data for all tenants...");
           tenantADataSource.connect();
           tenantBDataSource.connect();
       }
   }
Enter fullscreen mode Exit fullscreen mode

6. Retrieving TenantService from Context

  • Back in the main() method, the TenantService bean is retrieved from the Spring context:

     TenantService tenantService = context.getBean(TenantService.class);
    
  • This bean is fully initialized, with its dependencies injected.


7. Calling processTenantData()

  • The processTenantData() method is invoked on the TenantService bean.
  • Inside the method:
    • A message is printed: "Processing data for all tenants...".
    • The connect() method is called on both tenantADataSource and tenantBDataSource.

Code in main():

   tenantService.processTenantData();
Enter fullscreen mode Exit fullscreen mode

Code in TenantService:

   public void processTenantData() {
       System.out.println("Processing data for all tenants...");
       tenantADataSource.connect();
       tenantBDataSource.connect();
   }
Enter fullscreen mode Exit fullscreen mode

8. Connecting to Tenant Databases

  • For each TenantDataSource bean, the connect() method:

    • Prints the tenantName and databaseUrl:
       Connecting to database for tenant: tenantA
       Using database URL: jdbc:mysql://localhost:3306/tenantA_db
    
       Connecting to database for tenant: tenantB
       Using database URL: jdbc:mysql://localhost:3306/tenantB_db
    

Code in TenantDataSource:

   public void connect() {
       System.out.println("Connecting to database for tenant: " + tenantName);
       System.out.println("Using database URL: " + databaseUrl);
       // Simulate connection logic here
   }
Enter fullscreen mode Exit fullscreen mode

9. Program Completion

  • After processing data for both tenants, the program completes execution.

Complete Output:

Processing data for all tenants...
Connecting to database for tenant: tenantA
Using database URL: jdbc:mysql://localhost:3306/tenantA_db
Connecting to database for tenant: tenantB
Using database URL: jdbc:mysql://localhost:3306/tenantB_db
Enter fullscreen mode Exit fullscreen mode

More info at https://docs.spring.io/spring-framework/docs/6.2.2/javadoc-api/org/springframework/beans/factory/BeanFactory.html

Top comments (0)