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

AWS GenAI LIVE image

Real challenges. Real solutions. Real talk.

From technical discussions to philosophical debates, AWS and AWS Partners examine the impact and evolution of gen AI.

Learn more

Top comments (0)

Billboard image

Create up to 10 Postgres Databases on Neon's free plan.

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Try Neon for Free →

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay