Spring Boot使用@Profile
註解可以實現不同環境下配置參數的切換,任何@Component
或@Configuration
註解的類都可以使用@Profile
註解。
例如:
@Configuration
@Profile("production")
public class ProductionConfiguration {
// ...
}
通常,一個項目中可能會有多個profile場景,例如下面爲test場景:
@Configuration
@Profile("test")
public class TestConfiguration {
// ...
}
在存在多個profile情況下,你可以使用spring.profiles.active
來設置哪些profile被激活。spring.profiles.include
屬性用來設置無條件的激活哪些profile。
例如,你可以在application.properties
中設置:
或者在application.yaml
中設置:
spring.profiles.active
屬性可以通過命令行參數或者資源文件來設置,其查找順序,請參考Spring Boot特性。
自定義Profile註解
@Profile
註解需要接受一個字符串,作爲場景名。這樣每個地方都需要記住這個字符串。Spring的@Profile
註解支持定義在其他註解之上,以創建自定義場景註解。
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Profile("dev")
public @interface Dev {
}
這樣就創建了一個@Dev
註解,該註解可以標識bean使用於@Dev
這個場景。後續就不再需要使用@Profile("dev")
的方式。這樣即可以簡化代碼,同時可以利用IDE的自動補全:)
多個Profile例子
下面是一個例子:
package com.javachen.example.service;
public interface MessageService {
String getMessage();
}
對於MessageService接口,我們可以有生產和測試兩種實現:
package com.javachen.example.service;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
@Component
@Profile({ "dev" })
public class HelloWorldService implements MessageService{
@Value("${name:World}")
private String name;
public String getMessage() {
return "Hello " + this.name;
}
}
package com.javachen.example.service;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
@Component
@Profile({ "prod" })
public class GenericService implements MessageService {
@Value("${hello:Hello}")
private String hello;
@Value("${name:World}")
private String name;
@Override
public String getMessage() {
return this.hello + " " + this.name;
}
}
Application類爲:
@SpringBootApplication
public class Application implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(Application.class);
@Autowired
private MessageService messageService;
@Override
public void run(String... args) {
logger.info(this.messageService.getMessage());
if (args.length > 0 && args[0].equals("exitcode")) {
throw new ExitException();
}
}
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
實際使用中,使用哪個profile由spring.profiles.active
控制,你在resources/application.properties
中定義spring.profiles.active=XXX
,或者通過-Dspring.profiles.active=XXX
。XXX
可以是dev
或者prod
或者dev,prod
。需要注意的是
:本例中是將@Profile
用在Service類上,一個Service接口不能同時存在超過兩個實現類,故本例中不能同時使用dev和prod。
通過不同的profile,可以有對應的資源文件application-{profile}.properties
。例如,application-dev.properties
內容如下:
name=JavaChen-dev
application-prod.properties
內容如下:
接下來進行測試。spring.profiles.active=dev
時,運行Application類,查看日誌輸出。
2016-02-22 15:45:18,470 [main] INFO com.javachen.example.Application - Hello JavaChen-dev
spring.profiles.active=prod
時,運行Application類,查看日誌輸出。
2016-02-22 15:47:21,270 [main] INFO com.javachen.example.Application - Hello JavaChen-prod
logback配置多Profile
在resources目錄下添加logback-spring.xml,並分別對dev和prod進行配置:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--<include resource="org/springframework/boot/logging/logback/base.xml" />-->
<springProfile name="dev">
<logger name="com.javachen.example" level="TRACE" />
<appender name="LOGFILE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
</springProfile>
<springProfile name="prod">
<appender name="LOGFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>log/server.log</File>
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>log/server_%d{yyyy-MM-dd}.log.zip</FileNamePattern>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%date [%thread] %-5level %logger{80} - %msg%n</pattern>
</layout>
</appender>
</springProfile>
<root level="info">
<appender-ref ref="LOGFILE" />
</root>
<logger name="com.javachen.example" level="DEBUG" />
</configuration>
這樣,就可以做到不同profile場景下的日誌輸出不一樣。
maven中的場景配置
使用maven的resource filter可以實現多場景切換。
<profiles>
<profile>
<id>prod</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<build.profile.id>prod</build.profile.id>
</properties>
</profile>
<profile>
<id>dev</id>
<properties>
<build.profile.id>dev</build.profile.id>
</properties>
</profile>
</profiles>
<build>
<filters>
<filter>application-${build.profile.id}.properties</filter>
</filters>
<resources>
<resource>
<filtering>true</filtering>
<directory>src/main/resources</directory>
</resource>
</resources>
</build>
這樣在maven編譯時,可以通過-P
參數指定maven profile即可。
總結
使用Spring Boot的Profile註解可以實現多場景下的配置切換,方便開發中進行測試和部署生產環境。
本文中相關代碼在github上面。