SpringBoot2动态@Value怎么实现
SpringBoot2动态@Value怎么实现
本篇内容介绍了“SpringBoot2动态@Value怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
具体的实现步骤分为如下几步
1.通过BeanPostProcessor取得有使用@Value注解的bean,并存储到map中
2.动态修改map中的bean字段的值
获取bean
首先写一个类实现BeanPostProcessor接口,只需要使用其中的一个函数就可以。前后都可以用来实现,并不影响最终的使用,因为咱们只是需要bean的实例。
接下来看一下具体实现代码
packagecom.allen.apollo;importorg.springframework.beans.BeansException;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.beans.factory.config.BeanPostProcessor;importorg.springframework.context.annotation.Configuration;importorg.springframework.util.ReflectionUtils;importjava.lang.reflect.Field;importjava.util.LinkedList;importjava.util.List;importjava.util.Set;@ConfigurationpublicclassSpringValueProcessorimplementsBeanPostProcessor{privatefinalPlaceholderHelperplaceholderHelper=newPlaceholderHelper();@OverridepublicObjectpostProcessBeforeInitialization(Objectbean,StringbeanName)throwsBeansException{if(beanName.equals("springValueController")){Classobj=bean.getClass();List<Field>fields=findAllField(obj);for(Fieldfield:fields){Valuevalue=field.getAnnotation(Value.class);if(value!=null){Set<String>keys=placeholderHelper.extractPlaceholderKeys(value.value());for(Stringkey:keys){SpringValuespringValue=newSpringValue(key,value.value(),bean,beanName,field,false);SpringValueCacheMap.map.put(key,springValue);}}}}returnbean;}privateList<Field>findAllField(Classclazz){finalList<Field>res=newLinkedList<>();ReflectionUtils.doWithFields(clazz,newReflectionUtils.FieldCallback(){@OverridepublicvoiddoWith(Fieldfield)throwsIllegalArgumentException,IllegalAccessException{res.add(field);}});returnres;}}
上面的代码咱们就已经拿到了SpringValueController这个实例bean并存储到了map当中,下面看一下测试代码
/***cachefield,存储bean字段*/packagecom.allen.apollo;importcom.google.common.collect.LinkedListMultimap;importcom.google.common.collect.Multimap;publicclassSpringValueCacheMap{publicstaticfinalMultimap<String,SpringValue>map=LinkedListMultimap.create();}
packagecom.allen.apollo;importjava.lang.ref.WeakReference;importjava.lang.reflect.Field;importjava.lang.reflect.InvocationTargetException;importjava.lang.reflect.Method;importjava.lang.reflect.Type;importorg.springframework.core.MethodParameter;publicclassSpringValue{privateMethodParametermethodParameter;privateFieldfield;privateWeakReference<Object>beanRef;privateStringbeanName;privateStringkey;privateStringplaceholder;privateClass<?>targetType;privateTypegenericType;privatebooleanisJson;publicSpringValue(Stringkey,Stringplaceholder,Objectbean,StringbeanName,Fieldfield,booleanisJson){this.beanRef=newWeakReference<>(bean);this.beanName=beanName;this.field=field;this.key=key;this.placeholder=placeholder;this.targetType=field.getType();this.isJson=isJson;if(isJson){this.genericType=field.getGenericType();}}publicSpringValue(Stringkey,Stringplaceholder,Objectbean,StringbeanName,Methodmethod,booleanisJson){this.beanRef=newWeakReference<>(bean);this.beanName=beanName;this.methodParameter=newMethodParameter(method,0);this.key=key;this.placeholder=placeholder;Class<?>[]paramTps=method.getParameterTypes();this.targetType=paramTps[0];this.isJson=isJson;if(isJson){this.genericType=method.getGenericParameterTypes()[0];}}publicvoidupdate(ObjectnewVal)throwsIllegalAccessException,InvocationTargetException{if(isField()){injectField(newVal);}else{injectMethod(newVal);}}privatevoidinjectField(ObjectnewVal)throwsIllegalAccessException{Objectbean=beanRef.get();if(bean==null){return;}booleanaccessible=field.isAccessible();field.setAccessible(true);field.set(bean,newVal);field.setAccessible(accessible);}privatevoidinjectMethod(ObjectnewVal)throwsInvocationTargetException,IllegalAccessException{Objectbean=beanRef.get();if(bean==null){return;}methodParameter.getMethod().invoke(bean,newVal);}publicStringgetBeanName(){returnbeanName;}publicClass<?>getTargetType(){returntargetType;}publicStringgetPlaceholder(){returnthis.placeholder;}publicMethodParametergetMethodParameter(){returnmethodParameter;}publicbooleanisField(){returnthis.field!=null;}publicFieldgetField(){returnfield;}publicTypegetGenericType(){returngenericType;}publicbooleanisJson(){returnisJson;}booleanisTargetBeanValid(){returnbeanRef.get()!=null;}@OverridepublicStringtoString(){Objectbean=beanRef.get();if(bean==null){return"";}if(isField()){returnString.format("key:%s,beanName:%s,field:%s.%s",key,beanName,bean.getClass().getName(),field.getName());}returnString.format("key:%s,beanName:%s,method:%s.%s",key,beanName,bean.getClass().getName(),methodParameter.getMethod().getName());}}
packagecom.allen.apollo;importcom.google.common.base.Strings;importcom.google.common.collect.Sets;importorg.springframework.beans.factory.config.BeanDefinition;importorg.springframework.beans.factory.config.BeanExpressionContext;importorg.springframework.beans.factory.config.ConfigurableBeanFactory;importorg.springframework.beans.factory.config.Scope;importorg.springframework.util.StringUtils;importjava.util.Set;importjava.util.Stack;/***Placeholderhelperfunctions.*/publicclassPlaceholderHelper{privatestaticfinalStringPLACEHOLDER_PREFIX="${";privatestaticfinalStringPLACEHOLDER_SUFFIX="}";privatestaticfinalStringVALUE_SEPARATOR=":";privatestaticfinalStringSIMPLE_PLACEHOLDER_PREFIX="{";privatestaticfinalStringEXPRESSION_PREFIX="#{";privatestaticfinalStringEXPRESSION_SUFFIX="}";/***Resolveplaceholderpropertyvalues,e.g.*<br/>*<br/>*"${somePropertyValue}"->"theactualpropertyvalue"*/publicObjectresolvePropertyValue(ConfigurableBeanFactorybeanFactory,StringbeanName,Stringplaceholder){//resolvestringvalueStringstrVal=beanFactory.resolveEmbeddedValue(placeholder);BeanDefinitionbd=(beanFactory.containsBean(beanName)?beanFactory.getMergedBeanDefinition(beanName):null);//resolveexpressionslike"#{systemProperties.myProp}"returnevaluateBeanDefinitionString(beanFactory,strVal,bd);}privateObjectevaluateBeanDefinitionString(ConfigurableBeanFactorybeanFactory,Stringvalue,BeanDefinitionbeanDefinition){if(beanFactory.getBeanExpressionResolver()==null){returnvalue;}Scopescope=(beanDefinition!=null?beanFactory.getRegisteredScope(beanDefinition.getScope()):null);returnbeanFactory.getBeanExpressionResolver().evaluate(value,newBeanExpressionContext(beanFactory,scope));}/***Extractkeysfromplaceholder,e.g.*<ul>*<li>${some.key}=>"some.key"</li>*<li>${some.key:${some.other.key:100}}=>"some.key","some.other.key"</li>*<li>${${some.key}}=>"some.key"</li>*<li>${${some.key:other.key}}=>"some.key"</li>*<li>${${some.key}:${another.key}}=>"some.key","another.key"</li>*<li>#{newjava.text.SimpleDateFormat("${some.key}").parse("${another.key}")}=>"some.key","another.key"</li>*</ul>*/publicSet<String>extractPlaceholderKeys(StringpropertyString){Set<String>placeholderKeys=Sets.newHashSet();if(!isNormalizedPlaceholder(propertyString)&&!isExpressionWithPlaceholder(propertyString)){returnplaceholderKeys;}Stack<String>stack=newStack<>();stack.push(propertyString);while(!stack.isEmpty()){StringstrVal=stack.pop();intstartIndex=strVal.indexOf(PLACEHOLDER_PREFIX);if(startIndex==-1){placeholderKeys.add(strVal);continue;}intendIndex=findPlaceholderEndIndex(strVal,startIndex);if(endIndex==-1){//invalidplaceholder?continue;}StringplaceholderCandidate=strVal.substring(startIndex+PLACEHOLDER_PREFIX.length(),endIndex);//${some.key:other.key}if(placeholderCandidate.startsWith(PLACEHOLDER_PREFIX)){stack.push(placeholderCandidate);}else{//some.key:${some.other.key:100}intseparatorIndex=placeholderCandidate.indexOf(VALUE_SEPARATOR);if(separatorIndex==-1){stack.push(placeholderCandidate);}else{stack.push(placeholderCandidate.substring(0,separatorIndex));StringdefaultValuePart=normalizeToPlaceholder(placeholderCandidate.substring(separatorIndex+VALUE_SEPARATOR.length()));if(!Strings.isNullOrEmpty(defaultValuePart)){stack.push(defaultValuePart);}}}//hasremainingpart,e.g.${a}.${b}if(endIndex+PLACEHOLDER_SUFFIX.length()<strVal.length()-1){StringremainingPart=normalizeToPlaceholder(strVal.substring(endIndex+PLACEHOLDER_SUFFIX.length()));if(!Strings.isNullOrEmpty(remainingPart)){stack.push(remainingPart);}}}returnplaceholderKeys;}privatebooleanisNormalizedPlaceholder(StringpropertyString){returnpropertyString.startsWith(PLACEHOLDER_PREFIX)&&propertyString.endsWith(PLACEHOLDER_SUFFIX);}privatebooleanisExpressionWithPlaceholder(StringpropertyString){returnpropertyString.startsWith(EXPRESSION_PREFIX)&&propertyString.endsWith(EXPRESSION_SUFFIX)&&propertyString.contains(PLACEHOLDER_PREFIX);}privateStringnormalizeToPlaceholder(StringstrVal){intstartIndex=strVal.indexOf(PLACEHOLDER_PREFIX);if(startIndex==-1){returnnull;}intendIndex=strVal.lastIndexOf(PLACEHOLDER_SUFFIX);if(endIndex==-1){returnnull;}returnstrVal.substring(startIndex,endIndex+PLACEHOLDER_SUFFIX.length());}privateintfindPlaceholderEndIndex(CharSequencebuf,intstartIndex){intindex=startIndex+PLACEHOLDER_PREFIX.length();intwithinNestedPlaceholder=0;while(index<buf.length()){if(StringUtils.substringMatch(buf,index,PLACEHOLDER_SUFFIX)){if(withinNestedPlaceholder>0){withinNestedPlaceholder--;index=index+PLACEHOLDER_SUFFIX.length();}else{returnindex;}}elseif(StringUtils.substringMatch(buf,index,SIMPLE_PLACEHOLDER_PREFIX)){withinNestedPlaceholder++;index=index+SIMPLE_PLACEHOLDER_PREFIX.length();}else{index++;}}return-1;}}
packagecom.allen.apollo;importlombok.extern.slf4j.Slf4j;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.util.StringUtils;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RestController;importjava.lang.reflect.InvocationTargetException;@RestController@Slf4jpublicclassSpringValueController{@Value("${test:123}")publicStringzax;@Value("${test:123}")publicStringtest;@Value(("${zed:zed}"))publicStringzed;@GetMapping("/test")publicStringtest(Stringa,Stringb){if(!StringUtils.isEmpty(a)){try{for(SpringValuespringValue:SpringValueCacheMap.map.get("test")){springValue.update(a);}for(SpringValuespringValue:SpringValueCacheMap.map.get("zed")){springValue.update(b);}}catch(IllegalAccessException|InvocationTargetExceptione){e.printStackTrace();}}returnString.format("test:%s,zax:%s,zed:%s",test,zax,zed);}}
“SpringBoot2动态@Value怎么实现”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注恰卡编程网网站,小编将为大家输出更多高质量的实用文章!
推荐阅读
-
springboot实现基于aop的切面日志
本文实例为大家分享了springboot实现基于aop的切面日志的具体代码,供大家参考,具体内容如下通过aop的切面方式实现日志...
-
SpringBoot定时任务功能怎么实现
-
SpringBoot中的@Import注解怎么使用
-
SpringBoot整合Lombok及常见问题怎么解决
-
springboot图片验证码功能模块怎么实现
-
Springboot+SpringSecurity怎么实现图片验证码登录
-
SpringBoot注解的知识点有哪些
SpringBoot注解的知识点有哪些这篇“SpringBoot注...
-
SpringBoot2.x中management.security.enabled=false无效怎么解决
-
springboot怎么禁用某项健康检查
springboot怎么禁用某项健康检查今天小编给大家分享一下sp...
-
SpringBoot2怎么自定义端点