以数据源为例,在不同环境下,我们会需要代码提供不同的数据源bean。如:
如果我们通过修改代码的方式每次部署不同环境时就改一次对应的代码,你是不是会疯掉呢?(会!)
那怎么做能根据不同的环境来让我们的代码自动提供相应的数据源对象呢?
通过Spring为环境相关的bean所提供的解决方案,是根据环境来决定该创建那个bean和不该创建那个bean。要注意的是,Spring并不是在构建的时候做出这样的决策,而是等到运行时再来确定
。
Spring引入了bean profile的功能。要使用profile,首先要将所有不同的bean定义到一个或多个profile之中,在将应用部署到每个环境时,还要确保对应的profile处于激活(active
)的状态。
在Java配置中,可以使用@Profile注解指定某个bean属于哪一个profile。
例如,在配置类中,嵌入式数据库的DataSource可能会配置成如下所示:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;import javax.sql.DataSource;@Configuration
@Profile("dev")
public class DevelopmentProfileConfig {@Beanpublic DataSource dataSource() {return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).addScript("classpath:schema.sql").addScript("classpath:test-data.sql").build();}
}
类上添加了@Profile注解,它会告诉Spring这个配置类中 的bean只有在dev profile激活时才会创建。如果dev profile 没有激活,那么该类中带有@Bean注解的方法都会被忽略。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.jndi.JndiObjectFactoryBean;import javax.sql.DataSource;@Configuration
@Profile("prod")
public class ProductionProfileConfig {@Beanpublic DataSource dataSource() {JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean();jndiObjectFactoryBean.setJndiName("jdbc/myDS");jndiObjectFactoryBean.setResourceRef(true);jndiObjectFactoryBean.setProxyInterface(DataSource.class);return (DataSource) jndiObjectFactoryBean.getObject();}
}
类上添加了@Profile注解,它会告诉Spring这个配置类中 的bean只有在prod profile激活时才会创建。
上面说了@Profile注解在类级别上,现在我们看看将@Profile注解在方法级别上,可以将多个bean的声明放到同一个配置类之中,更方便的进行代码阅读。如下:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.jndi.JndiObjectFactoryBean;import javax.sql.DataSource;@Configuration
@Profile("prod")
public class DataSourceConfig {/*** 为dev profile装配的bean*/@Bean@Profile("dev")public DataSource embeddedDataSource() {return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).addScript("classpath:schema.sql").addScript("classpath:test-data.sql").build();}/*** 为prod profile装配的bean*/@Bean@Profile("prod")public DataSource jndiDataSource() {JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean();jndiObjectFactoryBean.setJndiName("jdbc/myDS");jndiObjectFactoryBean.setResourceRef(true);jndiObjectFactoryBean.setProxyInterface(DataSource.class);return (DataSource) jndiObjectFactoryBean.getObject();}
}
但是需要注意一点,尽管如上每个Datasource bean都被声明在一个配置类中,并且只有当规定的profile激活时,相应的bean才会被创建,但是在代码不断迭代开发的过程中,可能会有其他的bean并没有被开发人员声明在一个给定的profile范围内。对于没有指定profile的bean,它始终都会被创建,此类bean就与激活哪个profile没有关系了!
Spring在确定哪个profile处于激活状态时,需要依赖两个独立的属性:
spring.profiles.active
和spring.profiles.default
。
有多种方式来设置这2个属性: