Article directory
Source address of demo of this blog
https://github.com/suchahaerkang/spring-annotation.git
The role of @ profile
@Function of Profile: switch between different environments, and register different components to the container dynamically
Now there is a requirement. We all know that when we develop a project, we usually have development (dev), test (test) and production (prod) environments. The data sources of each environment are different. Now how can we only switch the environment and register the corresponding components to the container dynamically?
Let's start with the code
First, we introduce the package of data source into the project. Here we use c3p0. Then introduce a mysql driver package
<!-- https://mvnrepository.com/artifact/c3p0/c3p0 --> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.44</version> </dependency>
Write a configuration class to register three components in the container (develop data source devDataSource, test data source testDataSource, generate data source prodDataSource)
/** * @description: * @author: sukang * @date: 2020-03-08 12:40 */ @PropertySource(value = {"classpath:/db.properties"}) @Configuration public class MainConfigOfProfile { @Value("${database.username}") private String userName; @Value("${database.password}") private String password; @Value("${database.driver}") private String driver; @Bean("devDataSource") public DataSource dataSourceOfDev() throws PropertyVetoException { ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setJdbcUrl("http://localhost:3306/dev"); dataSource.setUser(userName); dataSource.setPassword(password); dataSource.setDriverClass(driver); return dataSource; } @Bean("testDataSource") public DataSource dataSourceOfTest() throws PropertyVetoException { ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setJdbcUrl("http://localhost:3306/test"); dataSource.setUser(userName); dataSource.setPassword(password); dataSource.setDriverClass(driver); return dataSource; } @Bean("prodDataSource") public DataSource dataSourceOfProd() throws PropertyVetoException { ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setJdbcUrl("http://localhost:3306/prod"); dataSource.setUser(userName); dataSource.setPassword(password); dataSource.setDriverClass(driver); return dataSource; } }
By default, all three data sources will be registered in the container
Write a test case
@Test public void test01(){ //Create container ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfProfile.class); //Get all the names of the components in the container as DataSource String[] beanNames = applicationContext.getBeanNamesForType(DataSource.class); for (String name : beanNames) { System.out.println(name); } }
Operation result
The test results show that all three data sources are registered in the container, but this is not what we want. We want to register what kind of data sources in what kind of environment. Next, we use the @ Profile annotation to implement this function, plus the @ Profile annotation's configuration class
/** * @description: * @author: sukang * @date: 2020-03-08 12:40 */ @PropertySource(value = {"classpath:/db.properties"}) @Configuration public class MainConfigOfProfile { @Value("${database.username}") private String userName; @Value("${database.password}") private String password; @Value("${database.driver}") private String driver; @Profile("dev") @Bean("devDataSource") public DataSource dataSourceOfDev() throws PropertyVetoException { ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/dev"); dataSource.setUser(userName); dataSource.setPassword(password); dataSource.setDriverClass(driver); return dataSource; } @Profile("test") @Bean("testDataSource") public DataSource dataSourceOfTest() throws PropertyVetoException { ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test"); dataSource.setUser(userName); dataSource.setPassword(password); dataSource.setDriverClass(driver); return dataSource; } @Profile("prod") @Bean("prodDataSource") public DataSource dataSourceOfProd() throws PropertyVetoException { ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/prod"); dataSource.setUser(userName); dataSource.setPassword(password); dataSource.setDriverClass(driver); return dataSource; } }
After adding @ Profile to the configuration class, it has no effect. You must activate an environment when starting the container to take effect
2 two ways to activate the environment
1) Using command line dynamic parameters, add '- Dspring.profiles.active=dev' to the virtual machine parameter location
Operation result
2) Another way is by writing code
@Test public void test02(){ //Create container call parameterless constructor AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); //Activate test environment applicationContext.getEnvironment().setActiveProfiles("test"); //Register MainConfigOfProfile component applicationContext.register(MainConfigOfProfile.class); //Refresh container applicationContext.refresh(); //Get all the names of the components in the container as DataSource String[] beanNames = applicationContext.getBeanNamesForType(DataSource.class); for (String name : beanNames) { System.out.println(name); } }
Operation result