文章目录
- 3、profile激活的优先级
- 4、profile的书写
- 二、案例
-
一、 @Profile注解使用说明
使用@profile注解的目的是未了多环境开发,比如开发环境使用dev, 生产环境使用prod,就可以使用@Profile注解实现不同的开发环境使用不同的数据源;
@profile注解 使用说明:
spring3.2之前 @Profile注解用在类上
spring3.2 之后 @Profile注解用在 方法上另外一种说法
在项目运行中,包括多种环境,例如线上环境prod(product)、开发环境dev(development)、测试环境test、提测环境qa、单元测试unitest等等。不同的环境需要进行不同的配置,从而在不同的场景中跑我们的程序。例如prod环境和dev环境通常需要连接不同的数据库、需要配置不同的日志输出配置。还有一些类和方法,在不同的环境下有不同的实现方式。
Spring Boot 对此提供了支持,一方面是注解@Profile,另一方面还有多资源配置文件。
@profile
注解的作用是指定类、方法、注解上,在特定的 Profile 环境生效,任何@Component
或@Configuration
注解的类都可以使用@Profile
注解。在使用DI来依赖注入的时候,能够根据@profile
标明的环境,将注入符合当前运行环境的相应的bean。使用要求:
- 可以在任何直接或间接使用
@Component和@Configuration
的类上作为一个类型注解使用@profile
@Profile
中需要指定一个字符串,约定生效的环境@Profile
作为元注解,用于组成自定义构造型注解@Profile
作为任何@Bean方法的方法级注解
1、
@Profile
的使用位置(1)
@Prifile
修饰类@Configuration @Profile("prod") public class JndiDataConfig { @Bean(destroyMethod="") public DataSource dataSource() throws Exception { Context ctx = new InitialContext(); return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource"); } }
(2)
@Profile
修饰方法@Configuration public class AppConfig { @Bean("dataSource") @Profile("dev") public DataSource standaloneDataSource() { return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.HSQL) .addScript("classpath:com/bank/config/sql/schema.sql") .addScript("classpath:com/bank/config/sql/test-data.sql") .build(); } @Bean("dataSource") @Profile("prod") public DataSource jndiDataSource() throws Exception { Context ctx = new InitialContext(); return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource"); } }
(3)
@Profile
修饰注解@Profile
注解支持定义在其他注解之上,以创建自定义场景注解。这样就创建了一个@Dev
注解,该注解可以标识bean使用于@Dev
这个场景。后续就不再需要使用@Profile("dev")
的方式,这样即可以简化代码。@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Profile("dev") public @interface Dev{ }
2、profile激活
实际使用中,注解中标示了prod、test、dev等多个环境,运行时使用哪个profile由spring.profiles.active控制,以下说明常见的几种方式。
(1)配置文件方式激活profile
确定当前使用的是哪个环境,这边环境的值与application-prod.properties中-后面的值对应,这是SpringBoot约定好的。
在resources/application.properties中添加下面的配置。需要注意的是,spring.profiles.active的取值应该与@Profile
注解中的标示保持一致。spring.profiles.active=dev
除此之外,同理还可以在resources/application.yml中配置,效果是一样的:
spring: profiles: active: dev
注意:
spring.profiles.active 激活方式 ,如果 spring.profiles.active 未配置,则使用spring.profiles.default激活方式。如果前面都没有配置,就会加载没有定义在profile中的bean
SpringBoot默认会加载并读取该配置,当发现为profile=dev时,会同时关联加载application-dev.properties这个配置。这种方式非常简单,可以实现对不同环境采用单独的配置文件进行隔离。
(2)命令行方式激活profile
在打包后运行的时候,添加参数:
(1)java -jar spring-boot-02-config-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev (2)java -jar application.jar -Dspring.profiles.active=dev (3)java -jar -Dspring.profiles.active=prod *.jar
(3)在web.xml 中配置
<context-param> <param-name>spring.profiles.active</param-name> <param-value>dev</param-value> </context-param> <servlet> <servlet-name>zszxzServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>spring.profiles.default</param-name> <param-value>dev</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>zszxzServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
(4)在类上使用@ActiveProfiles注解
@RunWith(SpringJUnit4ClassRunner.class)//创建spring应用上下文 @ContextConfiguration(classes= DataSourceConfig.class)//加载配置类 @ActiveProfiles("dev") public class ProfileTest { @Autowired private DataSource dataSource; @Test public void sheetTest(){ JdbcTemplate jdbc = new JdbcTemplate(dataSource); List<String> query = jdbc.query("select * from customer", new RowMapper<String>() { @Override public String mapRow(ResultSet rs, int rowNum) throws SQLException { return rs.getLong("id") + ":" + rs.getString("customer_name"); } }); // [19:知识追寻者, 20:知识追寻者, 21:知识追寻者, 22:知识追寻者, 23:知识追寻者] System.out.println(query); } }
(5)在 Java 代码中激活 profile
方式1:直接指定环境变量来激活 profile:
System.setProperty("spring.profiles.active", "test");
方式2:在 Spring 容器中激活 profile:
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.getEnvironment().setActiveProfiles("development"); ctx.register(SomeConfig.class, StandaloneDataConfig.class, JndiDataConfig.class); ctx.refresh();
方式3:实现WebApplicationInitializer接口
在Web应用程序中,通过WebApplicationInitializer可以对当前的ServletContext进行配置。
如下,通过注入spring.profiles.active变量可以为Spring上下文指定当前的 profile:@Configuration public class MyWebApplicationInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { servletContext.setInitParameter( "spring.profiles.active", "dev"); } }
方式4:使用 ConfigurableEnvironment
ConfigurableEnvironment 这个Bean封装了当前环境的配置信息,你可以在启动应用前进行设定操作:SpringApplication application = new SpringApplication(MyApplication.class); //设置environment中的profiler ConfigurableEnvironment environment = new StandardEnvironment(); environment.setActiveProfiles("dev","join_dev"); application.setEnvironment(environment); application.run(args)
方式5:SpringApplication.setAdditionalProfiles
SpringApplication这个类还提供了setAdditionalProfiles方法,用来让我们实现”附加”式的profile。
这些profile会同时被启用,而不是替换原来的active profile,如下:SpringApplication application = new SpringApplication(MyApplication.class); application.setAdditionalProfiles("new_dev");
注意:
这种方式可以实现无条件的启用profile,优先级是最高的。
当然,还可以通过设定spring.profiles.include来达到同样的目的。(6)通过环境变量的方式激活
在Unix/Linux环境中,可以通过环境变量注入profile的值: export spring_profiles_active=dev java -jar application.jar
(7)通过Maven的方式激活
Maven本身也提供了Profile的功能,可以通过Maven的Profile配置来指定Spring的Profile。
这种做法稍微有点复杂,需要先在pom.xml中设定不同的 maven profile,如下:<profiles> <profile> <id>dev</id> <activation> <activeByDefault>true</activeByDefault> </activation> <properties> <spring.profiles.active>dev</spring.profiles.active> </properties> </profile> <profile> <id>prod</id> <properties> <spring.profiles.active>prod</spring.profiles.active> </properties> </profile> </profiles>
这里,分别声明了dev和prod两个profile,每个profile都包含了一个spring.profiles.active属性,这个属性用来注入到 Spring中的profile入参。
在SpringBoot的配置文件application.properties中,需要替换为这个maven传入的property:使用Maven的属性进行替换 spring.profiles.active=@spring.profiles.active@
接下来,需要让Maven在打包时能将application.properties进行过滤处理,同时替换掉变量,需编辑pom.xml如下:
<build> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources> </build>
这里定义了filtering=true,因此Resource打包插件会对配置文件执行过滤。
如果你的项目pom定义继承自 spring-boot-starter-parent,那么可以不需要配置这个filter
最后,在maven打包时指定参数如下:mvn clean package -P prod
3、profile激活的优先级
至此,我们已经提供了很多种方法来设定 Spring应用的profile,当它们同时存在时则会根据一定优先级来抉择,参考如下:
(1)、SpringApplication.setAdditionalProfiles (2)、ConfigurableEnvironment、@ActiveProfiles (3)、Web.xml的 context-param (4)、WebApplicationInitializer (5)、JVM 启动参数 (6)、环境变量 (7)、Maven profile、application.properties 从上至下,优先级从高到低排列。
其中,Maven profile与配置文件的方式相同,环境变量以及JVM启动参数会覆盖配置文件的内容。
1和2则属于进程内的控制逻辑,优先级更高。
如果在启动SpringBoot应用前对当前ConfigurableEnvironment对象注入了profile,则会优先使用这个参数, ActiveProfiles用于测试环境,其原理与此类似。
SpringApplication.setAdditionalProfiles则是无论如何都会附加的profile,优先级最高。3、profile的书写
(1)单个环境名称
profile字符串可以包含简单的profile名称(例如”p1″) 或**profile表达式。 ** Profile表达式允许表达更复杂的profile逻辑, 例如”p1&p2″ 。
另外profile表达式支持以下运算符:
(1)、 ! – 逻辑非
(2) 、& – 逻辑并
(3).、| – 逻辑或(2)组合环境名称
当@Profile注解里配置多个环境时,记住需要使用大括号扩住, 例如:@Profile({“prod”, “dev”,”test”}) 这种用法等同于使用逻辑或。相当于在prod、dev、test三种环境里均可以产生效果。
3、案例:
(1)、通过@Profile注解匹配active参数,动态加载内部配置
@Profile可接受一个或者多个参数,例如:
@Profile({"test","prod"}) @Configuration public class WebConfig{ @Bean public Queue hello(){ return new Queue("hello"); } @Profile("receiver") @Bean public Receiver receiver(){ return new Receiver(); } @Profile("dev") @Bean public DevDemo dev(){ return new DevDemo (); }
当 spring.profiles.active=prod,dev 时,该配置类生效,且第一个@Bean和第三个@Bean生效
如果spring.profiles.active=prod ,则该配置文件生效,第一个@Bean生效
如果spring.profiles.active=dev ,该配置文件未生效,所以下面的@Bean都不会生效
如此,当我们的项目需要运行在不同环境,特异化配置又比较多,该注解的优势是相当明显的!(2) 配置不同环境的数据源
/** * @Author lsc * <p>spring3.2之前 @Profile注解用在类上 * spring3.2 之后 @Profile注解用在 方法上 * </p> */ @Configuration public class DataSourceConfig { @Bean @Profile("dev") public DataSource devDataSource() { System.out.println(" dev DataSource !!"); BasicDataSource basicDataSource = new BasicDataSource(); basicDataSource.setDriverClassName("com.mysql.jdbc.Driver"); basicDataSource.setUrl("jdbc:mysql://localhost:3308/zszxz"); basicDataSource.setUsername("root"); basicDataSource.setPassword("1234"); return basicDataSource; } @Bean @Profile("prod") public DataSource prodDataSource() { System.out.println(" prod DataSource !!"); BasicDataSource basicDataSource = new BasicDataSource(); basicDataSource.setDriverClassName("com.mysql.jdbc.Driver"); basicDataSource.setUrl("jdbc:mysql://localhost:3306/zszxz"); basicDataSource.setUsername("root"); basicDataSource.setPassword("1234"); return basicDataSource; } }
如果你是在xml中配置,示例如下
<beans profile="dev"> <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://localhost:3306/zszxzb" p:username="root" p:password="1234"/> </beans> <beans profile="prod"> <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://localhost:3306/zszxzb" p:username="root" p:password="1234"/> </beans>
鸣谢:
https://blog.csdn.net/loongkingwhat/article/details/105745303
https://www.jianshu.com/p/75de79fba705
https://www.cnblogs.com/huahua-test/p/11576907.html - 可以在任何直接或间接使用
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/150479.html