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 theAnnotationConfigApplicationContextclass withTenantConfig.classas 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(); } 2. Spring Context Initialization
- The
AnnotationConfigApplicationContextprocesses theTenantConfigclass annotated with@Configuration. It scans the package"org.example4"for components like@Serviceand 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(); } } 3. Bean Creation in TenantConfig
- Spring invokes the two
@Beanmethods (tenantADataSource()andtenantBDataSource()) to create two beans of typeTenantDataSource:"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(); } 4. TenantDataSource Bean Initialization
- The
TenantDataSourceclass implementsBeanNameAware, allowing the Spring container to call thesetBeanName(String beanName)method during bean initialization. - The
setBeanNamemethod extracts the tenant name (tenantAortenantB) 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 } } 5. TenantService Bean Creation
- Spring scans the package
"org.example4"and finds theTenantServiceclass annotated with@Service. - The
TenantServiceconstructor has dependencies annotated with@Qualifier, which specifies whichTenantDataSourcebeans 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(); } } 6. Retrieving TenantService from Context
-
Back in the
main()method, theTenantServicebean 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 theTenantServicebean. - Inside the method:
- A message is printed:
"Processing data for all tenants...". - The
connect()method is called on bothtenantADataSourceandtenantBDataSource.
- A message is printed:
Code in main():
tenantService.processTenantData(); Code in TenantService:
public void processTenantData() { System.out.println("Processing data for all tenants..."); tenantADataSource.connect(); tenantBDataSource.connect(); } 8. Connecting to Tenant Databases
-
For each
TenantDataSourcebean, theconnect()method:- Prints the
tenantNameanddatabaseUrl:
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 - Prints the
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 } 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 More info at https://docs.spring.io/spring-framework/docs/6.2.2/javadoc-api/org/springframework/beans/factory/BeanFactory.html
Top comments (0)