1: Define the bean class
@Configuration
public class ProfileTestConfiguration {
@Bean
@Profile(value = "dev")
public MyProfileBean devProfileBean() {
return new MyProfileBean("dev profile");
}
@Bean
@Profile(value = "test")
public MyProfileBean testProfileBean() {
return new MyProfileBean("test profile");
}
}
The above class @Profle
takes effect in which environment the bean is specified.
2: Test class
@SpringBootApplication(exclude = {
SpringApplicationAdminJmxAutoConfiguration.class })
@Import(ProfileTestConfiguration.class)
public class SpringbootHelloworldApplication {
public static void main(String[] args) {
ConfigurableApplicationContext cac = SpringApplication.run(SpringbootHelloworldApplication.class, args);
MyProfileBean myProfileBean = cac.getBean(MyProfileBean.class);
System.out.println(myProfileBean);
}
}
3: Modify to dev environment
modifyapplication.properties
spring.profiles.active=dev
test:
2021-01-31 16:35:05.269 INFO 80572 --- [ main] d.d.s.SpringbootHelloworldApplication : Started SpringbootHelloworldApplication in 3.907 seconds (JVM running for 5.498)
MyProfileBean{
name='dev profile'}
4: Modify to test environment
modifyapplication.properties
spring.profiles.active=test
test:
2021-01-31 17:14:33.127 INFO 81908 --- [ main] d.d.s.SpringbootHelloworldApplication : Started SpringbootHelloworldApplication in 5.172 seconds (JVM running for 6.953)
MyProfileBean{
name='test profile'}
5: Principle analysis
Look at the @Profile
source code of the annotations:
@Target({
ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ProfileCondition.class)
public @interface Profile {
String[] value();
}
You can see that it combines @Conditional
conditional annotations and will be ProfileCondition
used as a conditional class. The source code is as follows:
class ProfileCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
if (attrs != null) {
// 判断在配置文件中配置的spring.active.profile的值是否与@Profile注解给的value相同,
// 相同则为true,否则为false,为true时则加载,false则不加载
for (Object value : attrs.get("value")) {
if (context.getEnvironment().acceptsProfiles(Profiles.of((String[]) value))) {
return true;
}
}
return false;
}
return true;
}
}
Let's look at the org.springframework.context.annotation.Condition
source code again:
@FunctionalInterface
public interface Condition {
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
You can see that this is a functional interface, and there is only one method matches
that is to perform specific condition matching.
Let's look at the @Conditional
comments again, the source code is as follows:
@Target({
ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
Class<? extends Condition>[] value();
}
It @Target({ElementType.TYPE, ElementType.METHOD})
can be seen that this annotation can be used on classes and methods. This example is used on methods, such as the automatic configuration class in springboot, which is often used on classes.
Finally, in order to deepen the understanding, to translate the java config class as follows 注意不是可执行代码,只是为了示意
:
@Configuration
public class ProfileTestConfiguration {
if (spring.profiles.active=dev) {
@Bean
public MyProfileBean devProfileBean() {
return new MyProfileBean("dev profile");
}
}
if (spring.profiles.active=test) {
@Bean
@Profile(value = "test")
public MyProfileBean testProfileBean() {
return new MyProfileBean("test profile");
}
}
}
6: Define an example yourself
6.1: Define java config class
@Configuration
public class ProfileTestConfiguration {
@Bean
@MyConditionAnnotation(advantage = "帅")
public GirlFriend giveYouOneGirlFriend() {
return new GirlFriend("章子怡");
}
}
6.2: Define MyConditionAnnotation annotation
@Target({
ElementType.TYPE, ElementType.METHOD })
@Conditional(MyConditionalImpl.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyConditionAnnotation {
String advantage();
}
6.3: Define the Condition implementation class MyConditionalImpl
public class MyConditionalImpl implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 获取在@MyConditionAnnotation上设置的advantage的值,如果是"帅"则
// 如果是"丑"则为false
MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(MyConditionAnnotation.class.getName());
String advantage = attrs.get("advantage").get(0).toString();
System.out.println("advantage: " + advantage);
return "帅".equals(advantage);
}
}
Only the configuration is 帅
true.
6.4: Use @Import annotation to introduce configuration classes
@SpringBootApplication
@Import(ProfileTestConfiguration.class)
public class SpringbootHelloWorldApplication {
public static void main(String[] args) {
ConfigurableApplicationContext cac = SpringApplication.run(SpringbootHelloWorldApplication.class, args);
GirlFriend girlFriend = cac.getBean(GirlFriend.class);
System.out.println(girlFriend);
}
}
6.5: Testing
Because what we configure @MyConditionAnnotation(advantage = "帅")
should be true, test directly:
2021-01-31 20:11:00.357 INFO 88760 --- [ main] d.d.s.SpringbootHelloWorldApplication : The following profiles are active: test
advantage: 帅
...
d.s.SpringbootHelloWorldApplication : Started SpringbootHelloWorldApplication in 3.967 seconds (JVM running for 5.463)
GirlFriend{
name='章子怡'}
Amended to @MyConditionAnnotation(advantage = "丑")
test:
2021-01-31 20:13:31.277 INFO 88855 --- [ main] d.d.s.SpringbootHelloWorldApplication : The following profiles are active: test
advantage: 丑
...
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'dongshi.daddy.profiletest.GirlFriend' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:351)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:342)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1127)
at dongshi.daddy.springboothelloworld.SpringbootHelloWorldApplication.main(SpringbootHelloWorldApplication.java:16)
7: Condition implementation provided by spring5 by default
In spring5 the default provided org.springframework.context.annotation.ConfigurationCondition
, org.springframework.context.annotation.ProfileCondition
but precisely and only org.springframework.context.annotation.ProfileCondition
because the former is just an interface, not a concrete class, as shown below:
visible, did not get much attention in the spring, it has not been widely used, but In springboot, it has been carried forward in a wide range, and has become an important part of the automatic configuration of springboot's core functions. You can simply look at the many implementation classes in springboot: