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 theAnnotationConfigApplicationContext
class withTenantConfig.class
as its configuration.
Code:
<span>public</span> <span>static</span> <span>void</span> <span>main</span><span>(</span><span>String</span><span>[]</span> <span>args</span><span>)</span> <span>{</span><span>// Initialize Spring context</span><span>AnnotationConfigApplicationContext</span> <span>context</span> <span>=</span> <span>new</span> <span>AnnotationConfigApplicationContext</span><span>(</span><span>TenantConfig</span><span>.</span><span>class</span><span>);</span><span>TenantService</span> <span>tenantService</span> <span>=</span> <span>context</span><span>.</span><span>getBean</span><span>(</span><span>TenantService</span><span>.</span><span>class</span><span>);</span><span>// Process tenant data</span><span>tenantService</span><span>.</span><span>processTenantData</span><span>();</span><span>}</span><span>public</span> <span>static</span> <span>void</span> <span>main</span><span>(</span><span>String</span><span>[]</span> <span>args</span><span>)</span> <span>{</span> <span>// Initialize Spring context</span> <span>AnnotationConfigApplicationContext</span> <span>context</span> <span>=</span> <span>new</span> <span>AnnotationConfigApplicationContext</span><span>(</span><span>TenantConfig</span><span>.</span><span>class</span><span>);</span> <span>TenantService</span> <span>tenantService</span> <span>=</span> <span>context</span><span>.</span><span>getBean</span><span>(</span><span>TenantService</span><span>.</span><span>class</span><span>);</span> <span>// Process tenant data</span> <span>tenantService</span><span>.</span><span>processTenantData</span><span>();</span> <span>}</span>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 theTenantConfig
class annotated with@Configuration
. It scans the package"org.example4"
for components like@Service
and other Spring-managed beans.
Code:
<span>@Configuration</span><span>@ComponentScan</span><span>(</span><span>basePackages</span> <span>=</span> <span>"org.example4"</span><span>)</span> <span>// Adjust to your package structure</span><span>public</span> <span>class</span> <span>TenantConfig</span> <span>{</span><span>@Bean</span><span>(</span><span>name</span> <span>=</span> <span>"tenantA-dataSource"</span><span>)</span><span>public</span> <span>TenantDataSource</span> <span>tenantADataSource</span><span>()</span> <span>{</span><span>return</span> <span>new</span> <span>TenantDataSource</span><span>();</span><span>}</span><span>@Bean</span><span>(</span><span>name</span> <span>=</span> <span>"tenantB-dataSource"</span><span>)</span><span>public</span> <span>TenantDataSource</span> <span>tenantBDataSource</span><span>()</span> <span>{</span><span>return</span> <span>new</span> <span>TenantDataSource</span><span>();</span><span>}</span><span>}</span><span>@Configuration</span> <span>@ComponentScan</span><span>(</span><span>basePackages</span> <span>=</span> <span>"org.example4"</span><span>)</span> <span>// Adjust to your package structure</span> <span>public</span> <span>class</span> <span>TenantConfig</span> <span>{</span> <span>@Bean</span><span>(</span><span>name</span> <span>=</span> <span>"tenantA-dataSource"</span><span>)</span> <span>public</span> <span>TenantDataSource</span> <span>tenantADataSource</span><span>()</span> <span>{</span> <span>return</span> <span>new</span> <span>TenantDataSource</span><span>();</span> <span>}</span> <span>@Bean</span><span>(</span><span>name</span> <span>=</span> <span>"tenantB-dataSource"</span><span>)</span> <span>public</span> <span>TenantDataSource</span> <span>tenantBDataSource</span><span>()</span> <span>{</span> <span>return</span> <span>new</span> <span>TenantDataSource</span><span>();</span> <span>}</span> <span>}</span>@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()
andtenantBDataSource()
) to create two beans of typeTenantDataSource
:"tenantA-dataSource"
"tenantB-dataSource"
Code for @Bean
definitions:
<span>@Bean</span><span>(</span><span>name</span> <span>=</span> <span>"tenantA-dataSource"</span><span>)</span><span>public</span> <span>TenantDataSource</span> <span>tenantADataSource</span><span>()</span> <span>{</span><span>return</span> <span>new</span> <span>TenantDataSource</span><span>();</span><span>}</span><span>@Bean</span><span>(</span><span>name</span> <span>=</span> <span>"tenantB-dataSource"</span><span>)</span><span>public</span> <span>TenantDataSource</span> <span>tenantBDataSource</span><span>()</span> <span>{</span><span>return</span> <span>new</span> <span>TenantDataSource</span><span>();</span><span>}</span><span>@Bean</span><span>(</span><span>name</span> <span>=</span> <span>"tenantA-dataSource"</span><span>)</span> <span>public</span> <span>TenantDataSource</span> <span>tenantADataSource</span><span>()</span> <span>{</span> <span>return</span> <span>new</span> <span>TenantDataSource</span><span>();</span> <span>}</span> <span>@Bean</span><span>(</span><span>name</span> <span>=</span> <span>"tenantB-dataSource"</span><span>)</span> <span>public</span> <span>TenantDataSource</span> <span>tenantBDataSource</span><span>()</span> <span>{</span> <span>return</span> <span>new</span> <span>TenantDataSource</span><span>();</span> <span>}</span>@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 implementsBeanNameAware
, allowing the Spring container to call thesetBeanName(String beanName)
method during bean initialization. - The
setBeanName
method extracts the tenant name (tenantA
ortenantB
) from the bean name and assigns a corresponding database URL.
Code:
<span>public</span> <span>class</span> <span>TenantDataSource</span> <span>implements</span> <span>BeanNameAware</span> <span>{</span><span>private</span> <span>String</span> <span>tenantName</span><span>;</span><span>private</span> <span>String</span> <span>databaseUrl</span><span>;</span><span>@Override</span><span>public</span> <span>void</span> <span>setBeanName</span><span>(</span><span>String</span> <span>beanName</span><span>)</span> <span>{</span><span>// Extract tenant name from the bean name</span><span>if</span> <span>(</span><span>beanName</span><span>.</span><span>contains</span><span>(</span><span>"-"</span><span>))</span> <span>{</span><span>this</span><span>.</span><span>tenantName</span> <span>=</span> <span>beanName</span><span>.</span><span>split</span><span>(</span><span>"-"</span><span>)[</span><span>0</span><span>];</span><span>}</span> <span>else</span> <span>{</span><span>throw</span> <span>new</span> <span>IllegalArgumentException</span><span>(</span><span>"Invalid bean naming convention. Expected format: <tenantName>-dataSource"</span><span>);</span><span>}</span><span>// Assign a database URL dynamically based on the tenant name</span><span>this</span><span>.</span><span>databaseUrl</span> <span>=</span> <span>"jdbc:mysql://localhost:3306/"</span> <span>+</span> <span>tenantName</span> <span>+</span> <span>"_db"</span><span>;</span><span>}</span><span>public</span> <span>void</span> <span>connect</span><span>()</span> <span>{</span><span>System</span><span>.</span><span>out</span><span>.</span><span>println</span><span>(</span><span>"Connecting to database for tenant: "</span> <span>+</span> <span>tenantName</span><span>);</span><span>System</span><span>.</span><span>out</span><span>.</span><span>println</span><span>(</span><span>"Using database URL: "</span> <span>+</span> <span>databaseUrl</span><span>);</span><span>// Simulate connection logic here</span><span>}</span><span>}</span><span>public</span> <span>class</span> <span>TenantDataSource</span> <span>implements</span> <span>BeanNameAware</span> <span>{</span> <span>private</span> <span>String</span> <span>tenantName</span><span>;</span> <span>private</span> <span>String</span> <span>databaseUrl</span><span>;</span> <span>@Override</span> <span>public</span> <span>void</span> <span>setBeanName</span><span>(</span><span>String</span> <span>beanName</span><span>)</span> <span>{</span> <span>// Extract tenant name from the bean name</span> <span>if</span> <span>(</span><span>beanName</span><span>.</span><span>contains</span><span>(</span><span>"-"</span><span>))</span> <span>{</span> <span>this</span><span>.</span><span>tenantName</span> <span>=</span> <span>beanName</span><span>.</span><span>split</span><span>(</span><span>"-"</span><span>)[</span><span>0</span><span>];</span> <span>}</span> <span>else</span> <span>{</span> <span>throw</span> <span>new</span> <span>IllegalArgumentException</span><span>(</span><span>"Invalid bean naming convention. Expected format: <tenantName>-dataSource"</span><span>);</span> <span>}</span> <span>// Assign a database URL dynamically based on the tenant name</span> <span>this</span><span>.</span><span>databaseUrl</span> <span>=</span> <span>"jdbc:mysql://localhost:3306/"</span> <span>+</span> <span>tenantName</span> <span>+</span> <span>"_db"</span><span>;</span> <span>}</span> <span>public</span> <span>void</span> <span>connect</span><span>()</span> <span>{</span> <span>System</span><span>.</span><span>out</span><span>.</span><span>println</span><span>(</span><span>"Connecting to database for tenant: "</span> <span>+</span> <span>tenantName</span><span>);</span> <span>System</span><span>.</span><span>out</span><span>.</span><span>println</span><span>(</span><span>"Using database URL: "</span> <span>+</span> <span>databaseUrl</span><span>);</span> <span>// Simulate connection logic here</span> <span>}</span> <span>}</span>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 theTenantService
class annotated with@Service
. - The
TenantService
constructor has dependencies annotated with@Qualifier
, which specifies whichTenantDataSource
beans to inject:"tenantA-dataSource"
"tenantB-dataSource"
Code:
<span>@Service</span><span>public</span> <span>class</span> <span>TenantService</span> <span>{</span><span>private</span> <span>final</span> <span>TenantDataSource</span> <span>tenantADataSource</span><span>;</span><span>private</span> <span>final</span> <span>TenantDataSource</span> <span>tenantBDataSource</span><span>;</span><span>@Autowired</span><span>public</span> <span>TenantService</span><span>(</span><span>@Qualifier</span><span>(</span><span>"tenantA-dataSource"</span><span>)</span> <span>TenantDataSource</span> <span>tenantADataSource</span><span>,</span><span>@Qualifier</span><span>(</span><span>"tenantB-dataSource"</span><span>)</span> <span>TenantDataSource</span> <span>tenantBDataSource</span><span>)</span> <span>{</span><span>this</span><span>.</span><span>tenantADataSource</span> <span>=</span> <span>tenantADataSource</span><span>;</span><span>this</span><span>.</span><span>tenantBDataSource</span> <span>=</span> <span>tenantBDataSource</span><span>;</span><span>}</span><span>public</span> <span>void</span> <span>processTenantData</span><span>()</span> <span>{</span><span>System</span><span>.</span><span>out</span><span>.</span><span>println</span><span>(</span><span>"Processing data for all tenants..."</span><span>);</span><span>tenantADataSource</span><span>.</span><span>connect</span><span>();</span><span>tenantBDataSource</span><span>.</span><span>connect</span><span>();</span><span>}</span><span>}</span><span>@Service</span> <span>public</span> <span>class</span> <span>TenantService</span> <span>{</span> <span>private</span> <span>final</span> <span>TenantDataSource</span> <span>tenantADataSource</span><span>;</span> <span>private</span> <span>final</span> <span>TenantDataSource</span> <span>tenantBDataSource</span><span>;</span> <span>@Autowired</span> <span>public</span> <span>TenantService</span><span>(</span> <span>@Qualifier</span><span>(</span><span>"tenantA-dataSource"</span><span>)</span> <span>TenantDataSource</span> <span>tenantADataSource</span><span>,</span> <span>@Qualifier</span><span>(</span><span>"tenantB-dataSource"</span><span>)</span> <span>TenantDataSource</span> <span>tenantBDataSource</span> <span>)</span> <span>{</span> <span>this</span><span>.</span><span>tenantADataSource</span> <span>=</span> <span>tenantADataSource</span><span>;</span> <span>this</span><span>.</span><span>tenantBDataSource</span> <span>=</span> <span>tenantBDataSource</span><span>;</span> <span>}</span> <span>public</span> <span>void</span> <span>processTenantData</span><span>()</span> <span>{</span> <span>System</span><span>.</span><span>out</span><span>.</span><span>println</span><span>(</span><span>"Processing data for all tenants..."</span><span>);</span> <span>tenantADataSource</span><span>.</span><span>connect</span><span>();</span> <span>tenantBDataSource</span><span>.</span><span>connect</span><span>();</span> <span>}</span> <span>}</span>@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, theTenantService
bean is retrieved from the Spring context:<span>TenantService</span> <span>tenantService</span> <span>=</span> <span>context</span><span>.</span><span>getBean</span><span>(</span><span>TenantService</span><span>.</span><span>class</span><span>);</span><span>TenantService</span> <span>tenantService</span> <span>=</span> <span>context</span><span>.</span><span>getBean</span><span>(</span><span>TenantService</span><span>.</span><span>class</span><span>);</span>
TenantService tenantService = context.getBean(TenantService.class);
-
This bean is fully initialized, with its dependencies injected.
7. Calling processTenantData()
- The
processTenantData()
method is invoked on theTenantService
bean. - Inside the method:
- A message is printed:
"Processing data for all tenants..."
. - The
connect()
method is called on bothtenantADataSource
andtenantBDataSource
.
- A message is printed:
Code in main()
:
<span>tenantService</span><span>.</span><span>processTenantData</span><span>();</span><span>tenantService</span><span>.</span><span>processTenantData</span><span>();</span>tenantService.processTenantData();
Enter fullscreen mode Exit fullscreen mode
Code in TenantService
:
<span>public</span> <span>void</span> <span>processTenantData</span><span>()</span> <span>{</span><span>System</span><span>.</span><span>out</span><span>.</span><span>println</span><span>(</span><span>"Processing data for all tenants..."</span><span>);</span><span>tenantADataSource</span><span>.</span><span>connect</span><span>();</span><span>tenantBDataSource</span><span>.</span><span>connect</span><span>();</span><span>}</span><span>public</span> <span>void</span> <span>processTenantData</span><span>()</span> <span>{</span> <span>System</span><span>.</span><span>out</span><span>.</span><span>println</span><span>(</span><span>"Processing data for all tenants..."</span><span>);</span> <span>tenantADataSource</span><span>.</span><span>connect</span><span>();</span> <span>tenantBDataSource</span><span>.</span><span>connect</span><span>();</span> <span>}</span>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, theconnect()
method:- Prints the
tenantName
anddatabaseUrl
:
Connecting to database for tenant: tenantAUsing database URL: jdbc:mysql://localhost:3306/tenantA_dbConnecting to database for tenant: tenantBUsing database URL: jdbc:mysql://localhost:3306/tenantB_dbConnecting 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
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
:
<span>public</span> <span>void</span> <span>connect</span><span>()</span> <span>{</span><span>System</span><span>.</span><span>out</span><span>.</span><span>println</span><span>(</span><span>"Connecting to database for tenant: "</span> <span>+</span> <span>tenantName</span><span>);</span><span>System</span><span>.</span><span>out</span><span>.</span><span>println</span><span>(</span><span>"Using database URL: "</span> <span>+</span> <span>databaseUrl</span><span>);</span><span>// Simulate connection logic here</span><span>}</span><span>public</span> <span>void</span> <span>connect</span><span>()</span> <span>{</span> <span>System</span><span>.</span><span>out</span><span>.</span><span>println</span><span>(</span><span>"Connecting to database for tenant: "</span> <span>+</span> <span>tenantName</span><span>);</span> <span>System</span><span>.</span><span>out</span><span>.</span><span>println</span><span>(</span><span>"Using database URL: "</span> <span>+</span> <span>databaseUrl</span><span>);</span> <span>// Simulate connection logic here</span> <span>}</span>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: tenantAUsing database URL: jdbc:mysql://localhost:3306/tenantA_dbConnecting to database for tenant: tenantBUsing database URL: jdbc:mysql://localhost:3306/tenantB_dbProcessing 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_dbProcessing 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
暂无评论内容