Spring @Profile注解使用和源码解析 - 刘牌
source link: https://www.cnblogs.com/steakliu/p/17315703.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
在之前的文章中,写了一篇使用Spring @Profile实现开发环境,测试环境,生产环境的切换,之前的文章是使用SpringBoot项目搭建,实现了不同环境数据源的切换,在我们实际开发中,会分为dev,test,prod等环境,他们之间数独立的,今天进来详解介绍Spring @Profile的原理。
# Spring注解@Profile实现开发环境,测试环境,生产环境的切换
带有@Profile的注解的bean的不会被注册进IOC容器,需要为其设置环境变量激活,才能注册进IOC容器,如下通过setActiveProfiles设置了dev值,那么这三个值所对应的Bean会被注册进IOC容器。当然,我们在实际使用中,不会这样去做,使用SpringBoot的话,我们一般是使用yml,在yml中配置spring.profiles.active
,也可以通过配置jvm参数。
通过Environment设置profile
我们可以直接通过Environment来设置环境属性,这是比较原生的方法。
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.getEnvironment().setActiveProfiles("dev");
通过JVM参数设置
可以通过JVM参数来设置环境变量的值,在开发中,这种方式也是使用得比较普遍。
SpringBoot通过yml进行配置
在SpringBoot项目中,我们得配置项一般都是配置在yml文件中,这样就能和代码分开,并且也能进行动态配置。
从上面我们看出可以通过好几种方式进行配置,但是他们最终其实都是将环境变量设置进Environment
中,这样,spring在后续得流程里面,就能从Environment中获取环境变量,然后进行相应的逻辑处理。
BeanDefinition注册
首先,需要注册bean的元信息BeanDefinition,不过对于@Profile标注的方法,如果环境变量中有对应的变量值,那么就能注册,没有的话则不会进行注册,我们来看关键的代码,在ConfigurationClassBeanDefinitionReader中,有一个shouldSkip
判断,它会筛选出符合的bean,不符合条件的bean则被加入skippedBeanMethods集合中,不会被注册。
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
ConfigurationClass configClass = beanMethod.getConfigurationClass();
MethodMetadata metadata = beanMethod.getMetadata();
String methodName = metadata.getMethodName();
// Do we need to mark the bean as skipped by its condition?
if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
configClass.skippedBeanMethods.add(methodName);
return;
}
if (configClass.skippedBeanMethods.contains(methodName)) {
return;
}
}
shouldSkip源码
在shouldSkip中,会使用Condition接口,@Profile使用的是ProfileCondition
,然后调用matches
方法。
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationCondition.ConfigurationPhase phase) {
for (Condition condition : conditions) {
ConfigurationCondition.ConfigurationPhase requiredPhase = null;
if (condition instanceof ConfigurationCondition configurationCondition) {
requiredPhase = configurationCondition.getConfigurationPhase();
}
if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
return true;
}
}
return false;
}
ProfileCondition匹配
在ProfileCondition的matches方法中,主要就是去Environment中寻找环境变量,然后解析@Profile注解设置的value值,如果Environment中激活的配置中包含当前的配置,包含则能为true,不包含则为false,如上通过setActiveProfiles设置Environment中激活的配置为dev,当前传过来的配置为dev,那么就能匹配上,就能装配进IOC容器。
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
if (attrs != null) {
for (Object value : attrs.get("value")) {
if (context.getEnvironment().acceptsProfiles(Profiles.of((String[]) value))) {
return true;
}
}
return false;
}
return true;
}
从源码可以看出,其最核心的思想就是是否注册bean的元信息BeanDefinition,因为只有注册了BeanDefinition,后续才能为创建bean提供元数据支持,判断是否注册bean元信息,主要就是从Environment中取出profiles的值,然后和@Profile注解设置的值进行匹配,匹配得上就注册,bean不上就不注册。
上面我们对@Profile的使用做了详细的介绍,并对它的核心源码进行解剖,无非就是判断是否要注册BeanDefinition,如果我们需要做一些环境隔离的工作,使用@Profile还是比较不错的。
今天的分享就到这里,感谢你的观看,下期见!
Recommend
-
41
好看记得加个“星标”哈!其实最近都在研究事务相关的内容,之所以写这么一篇文章是因为前面写了一篇关于循环依赖的文章:《
-
11
在之前的《使用Sentinel实现接口限流》一文中,我们仅依靠引入Spring Cloud Alibaba对Sentinel的整合封装spring-cloud-starter-alibaba-sentinel,就完成了对所有Sprin...
-
5
使用Spring注解来注入属性
-
2
Spring-使用注解开发发布于 今天 17:54 在Spring4之后,要使用注解开发,必须要保证aop的包导入了
-
7
spring源码解析:元注解功能的实现 众所周知,...
-
8
白话谈区块链和其应用场景 这篇文章半年...
-
7
消费组使kafka中很重的概念,只有弄清楚消费组的概念,才能在项...
-
1
今天聊一聊spring中很重要的两个扩展点BeanPostProcessor和BeanFactoryPostProcessor,spring之所以如次强大,是因为它提供了丰富的功能给我们使用,但是我觉得最强大的是它扩展点,因为有了各种扩展点,我们才能去开发一些自己的需求,一个框架的强大之处也在于它能...
-
8
今天分享一下spring bean的作用域,理解bean的作用域能够在使用过程中避免一些问题,bean的作用域也是spring bean创建过程中一个重要的点。 Spring bean的作用域类型 singleton(单例模式):在整个应用程序...
-
6
你好,我是刘牌! 人生做事情失败了,拍拍裤子,站起来再试试,那么为啥软件中请求失败了为何就放弃了,而不是不再试试呢! 今天分享一下重试操作,我们知道网络是不可靠的,那么在进行网络请求时,难免...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK