vs 网站开发 mvc,如何在12366网站上做实名认证,哪些网站是python做的,建筑设计自学网对于springboot配置自动刷新#xff0c;原理也很简单#xff0c;就是在启动过程中用一个BeanPostProcessor去收集需要自动刷新的字段#xff0c;然后在springboot启动后开启轮询任务即可。 不过需要对之前的代码再次做修改#xff0c;因为springboot的配置注入value(…对于springboot配置自动刷新原理也很简单就是在启动过程中用一个BeanPostProcessor去收集需要自动刷新的字段然后在springboot启动后开启轮询任务即可。 不过需要对之前的代码再次做修改因为springboot的配置注入value(${})允许多个${}和嵌套所以不能确定简单的确定用到了那个配置本文为了简单就把所有的配置都认为需要动态刷新实际用的时候可以在application.yml中配置需要动态刷新的配置id列表。代码在https://gitee.com/summer-cat001/config-center。其中设计到的原理都在之前的一篇文章中感兴趣可以去看看springboot配置注入增强二属性注入的原理_springboot bean属性增强-CSDN博客
新增注解
Target({ElementType.FIELD, ElementType.TYPE})
Retention(RetentionPolicy.RUNTIME)
Documented
public interface ConfigRefresh {
}加上这个注解的字段并且字段上有value注解就会自动刷新
收集自动刷新的字段
这里会收集自动刷新的字段并加到ConfigCenterClient的refreshFieldValueList中。长轮询会从这里取数据进行对比如果发生变化就更新bean中的字段
Slf4j
public class ConfigRefreshAnnotationBeanPostProcessor implements ApplicationRunner, BeanPostProcessor, BeanFactoryAware, EnvironmentAware {private Environment environment;private ConfigurableBeanFactory beanFactory;Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {if (!(beanFactory instanceof ConfigurableBeanFactory)) {log.warn(ConfigurableBeanFactory requires a ConfigurableListableBeanFactory);return;}this.beanFactory (ConfigurableBeanFactory) beanFactory;}Overridepublic Object postProcessBeforeInitialization(Object bean, final String beanName) throws BeansException {if (beanFactory ! null) {ReflectionUtils.doWithFields(bean.getClass(), field - {try {ConfigRefresh configRefresh AnnotationUtils.getAnnotation(field, ConfigRefresh.class);if (configRefresh null) {return;}Value valueAnnotation AnnotationUtils.getAnnotation(field, Value.class);if (valueAnnotation null) {return;}String value valueAnnotation.value();String relValue beanFactory.resolveEmbeddedValue(value);ConfigCenterClient configCenterClient ConfigCenterClient.getInstance(null);configCenterClient.addRefreshFieldValue(bean, field, relValue);} catch (Exception e) {log.error(set bean field fail,beanName:{},fieldName:{}, bean.getClass().getName(), field.getName(), e);}});}return bean;}Overridepublic void setEnvironment(Environment environment) {this.environment environment;}Overridepublic void run(ApplicationArguments args) {ConfigCenterClient configCenterClient ConfigCenterClient.getInstance(null);configCenterClient.startSpringBootLongPolling((ConfigurableEnvironment) environment, beanFactory);}
}
把该bean注入到springboot中即在spring.factories中加入自动注入
org.springframework.boot.autoconfigure.EnableAutoConfigurationcom.config.center.autoconfigure.ConfigAutoConfiguration
这是一个ImportSelector会自动注入返回的类
Import(ConfigAutoConfiguration.class)
public class ConfigAutoConfiguration implements ImportSelector {Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {return new String[]{ConfigRefreshAnnotationBeanPostProcessor.class.getName()};}
}
启动长轮询
springboot启动完成后会发一个ApplicationRunner事件我们只要在实现这个接口的bean中启动即可
Overridepublic void run(ApplicationArguments args) {ConfigCenterClient configCenterClient ConfigCenterClient.getInstance(null);configCenterClient.startSpringBootLongPolling((ConfigurableEnvironment) environment, beanFactory);} public void startSpringBootLongPolling(ConfigurableEnvironment environment, ConfigurableBeanFactory beanFactory) {if (configMap.isEmpty() || refreshFieldValueList.isEmpty()) {log.info(configMap.size:{} refreshFieldValueList.size:{}, configMap.size(), refreshFieldValueList.size());return;}MutablePropertySources propertySources environment.getPropertySources();MapPropertySource configCenter (MapPropertySource) propertySources.get(PROPERTY_SOURCE_NAME);if (configCenter null) {log.warn(configCenter is null);return;}MapString, Object source configCenter.getSource();Thread thread new Thread(() - {while (!Thread.interrupted()) {try {MapString, Integer configIdMap configMap.values().stream().collect(Collectors.toMap(c - c.getId() , ConfigBO::getVersion));HttpRespBO httpRespBO HttpUtil.httpPostJson(url /config/change/get/long, JSON.toJSONString(configIdMap), 30000);ListConfigVO configList httpResp2ConfigVOList(httpRespBO);if (configList.isEmpty()) {continue;}configList.forEach(configVO - {MapString, Object result new HashMap();DataTransUtil.buildFlattenedMap(result, configVO.getConfigData(), );ConfigBO configBO this.configMap.get(configVO.getId());configBO.setVersion(configVO.getVersion());ListConfigDataBO configDataList configBO.getConfigDataList();MapString, ConfigDataBO configDataMap configDataList.stream().collect(Collectors.toMap(ConfigDataBO::getKey, Function.identity()));result.forEach((key, value) - {ConfigDataBO configDataBO configDataMap.get(key);if (configDataBO null) {configDataList.add(new ConfigDataBO(key, value.toString()));} else {configDataBO.setValue(value.toString());source.put(key, value);}});});refreshFieldValueList.forEach(refreshFieldBO - {try {Field field refreshFieldBO.getField();Value valueAnnotation AnnotationUtils.getAnnotation(field, Value.class);if (valueAnnotation null) {return;}String value valueAnnotation.value();String relValue beanFactory.resolveEmbeddedValue(value);if(relValue.equals(refreshFieldBO.getValue())){return;}field.setAccessible(true);field.set(refreshFieldBO.getBean(), relValue);} catch (Exception e) {log.error(startSpringBootLongPolling set Field error, e);}});} catch (Exception e) {log.error(startSpringBootLongPolling error, e);}}});thread.setName(startSpringBootLongPolling);thread.setDaemon(true);thread.start();}
效果
Value
Data
Component
public class ConfigTest {ConfigRefreshValue(${user.name})private String name;} Autowiredprivate ConfigTest configTest;Testpublic void configTest() throws InterruptedException {while (true) {System.out.println(configTest.getName());Thread.sleep(1000);}} ConfigurationProperties
增加同时有ConfigurationProperties和ConfigRefresh的收集
ConfigRefresh configRefresh AnnotationUtils.findAnnotation(bean.getClass(), ConfigRefresh.class);if (configRefresh ! null) {ConfigurationProperties configurationProperties AnnotationUtils.findAnnotation(bean.getClass(), ConfigurationProperties.class);if (configurationProperties ! null) {ConfigCenterClient configCenterClient ConfigCenterClient.getInstance(null);configCenterClient.addRefreshBeanList(bean);}}
在长轮询的返回中对ConfigurationProperties重新绑定
refreshBeanList.forEach(refreshBean - {ConfigurationProperties configurationProperties AnnotationUtils.findAnnotation(refreshBean.getClass(), ConfigurationProperties.class);if (configurationProperties null) {log.warn(refreshBeanList refreshBean configurationProperties is null, class:{}, refreshBean.getClass());return;}Binder binder Binder.get(environment);binder.bind(configurationProperties.prefix(), Bindable.ofInstance(refreshBean));});
完整代码
Slf4j
public class ConfigRefreshAnnotationBeanPostProcessor implements ApplicationRunner, BeanPostProcessor, BeanFactoryAware, EnvironmentAware {private Environment environment;private ConfigurableBeanFactory beanFactory;Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {if (!(beanFactory instanceof ConfigurableBeanFactory)) {log.warn(ConfigurableBeanFactory requires a ConfigurableListableBeanFactory);return;}this.beanFactory (ConfigurableBeanFactory) beanFactory;}Overridepublic Object postProcessBeforeInitialization(Object bean, final String beanName) throws BeansException {if (beanFactory ! null) {ReflectionUtils.doWithFields(bean.getClass(), field - {try {ConfigRefresh configRefresh AnnotationUtils.getAnnotation(field, ConfigRefresh.class);if (configRefresh null) {return;}Value valueAnnotation AnnotationUtils.getAnnotation(field, Value.class);if (valueAnnotation null) {return;}String value valueAnnotation.value();String relValue beanFactory.resolveEmbeddedValue(value);ConfigCenterClient configCenterClient ConfigCenterClient.getInstance(null);configCenterClient.addRefreshFieldValue(bean, field, relValue);} catch (Exception e) {log.error(set bean field fail,beanName:{},fieldName:{}, bean.getClass().getName(), field.getName(), e);}});ConfigRefresh configRefresh AnnotationUtils.findAnnotation(bean.getClass(), ConfigRefresh.class);if (configRefresh ! null) {ConfigurationProperties configurationProperties AnnotationUtils.findAnnotation(bean.getClass(), ConfigurationProperties.class);if (configurationProperties ! null) {ConfigCenterClient configCenterClient ConfigCenterClient.getInstance(null);configCenterClient.addRefreshBeanList(bean);}}}return bean;}Overridepublic void setEnvironment(Environment environment) {this.environment environment;}Overridepublic void run(ApplicationArguments args) {ConfigCenterClient configCenterClient ConfigCenterClient.getInstance(null);configCenterClient.startSpringBootLongPolling((ConfigurableEnvironment) environment, beanFactory);}
} public void startSpringBootLongPolling(ConfigurableEnvironment environment, ConfigurableBeanFactory beanFactory) {if (configMap.isEmpty() || refreshFieldValueList.isEmpty()) {log.info(configMap.size:{} refreshFieldValueList.size:{}, configMap.size(), refreshFieldValueList.size());return;}MutablePropertySources propertySources environment.getPropertySources();MapPropertySource configCenter (MapPropertySource) propertySources.get(PROPERTY_SOURCE_NAME);if (configCenter null) {log.warn(configCenter is null);return;}MapString, Object source configCenter.getSource();Thread thread new Thread(() - {while (!Thread.interrupted()) {try {MapString, Integer configIdMap configMap.values().stream().collect(Collectors.toMap(c - c.getId() , ConfigBO::getVersion));HttpRespBO httpRespBO HttpUtil.httpPostJson(url /config/change/get/long, JSON.toJSONString(configIdMap), 30000);ListConfigVO configList httpResp2ConfigVOList(httpRespBO);if (configList.isEmpty()) {continue;}configList.forEach(configVO - {MapString, Object result new HashMap();DataTransUtil.buildFlattenedMap(result, configVO.getConfigData(), );ConfigBO configBO this.configMap.get(configVO.getId());configBO.setVersion(configVO.getVersion());ListConfigDataBO configDataList configBO.getConfigDataList();MapString, ConfigDataBO configDataMap configDataList.stream().collect(Collectors.toMap(ConfigDataBO::getKey, Function.identity()));result.forEach((key, value) - {ConfigDataBO configDataBO configDataMap.get(key);if (configDataBO null) {configDataList.add(new ConfigDataBO(key, value.toString()));} else {configDataBO.setValue(value.toString());source.put(key, value);}});});refreshFieldValueList.forEach(refreshFieldBO - {try {Field field refreshFieldBO.getField();Value valueAnnotation AnnotationUtils.getAnnotation(field, Value.class);if (valueAnnotation null) {return;}String value valueAnnotation.value();String relValue beanFactory.resolveEmbeddedValue(value);if (relValue.equals(refreshFieldBO.getValue())) {return;}field.setAccessible(true);field.set(refreshFieldBO.getBean(), relValue);} catch (Exception e) {log.error(startSpringBootLongPolling set Field error, e);}});refreshBeanList.forEach(refreshBean - {ConfigurationProperties configurationProperties AnnotationUtils.findAnnotation(refreshBean.getClass(), ConfigurationProperties.class);if (configurationProperties null) {log.warn(refreshBeanList refreshBean configurationProperties is null, class:{}, refreshBean.getClass());return;}Binder binder Binder.get(environment);binder.bind(configurationProperties.prefix(), Bindable.ofInstance(refreshBean));});} catch (Exception e) {log.error(startSpringBootLongPolling error, e);}}});thread.setName(startSpringBootLongPolling);thread.setDaemon(true);thread.start();}
效果
Component
ConfigRefresh
ConfigurationProperties(prefix user)
public class ConfigTest2 {private String name;private int age;private ListString education;public String getName() {return name;}public void setName(String name) {this.name name;}public int getAge() {return age;}public void setAge(int age) {this.age age;}public ListString getEducation() {return education;}public void setEducation(ListString education) {this.education education;}
}Autowiredprivate ConfigTest2 configTest2;Testpublic void configTest() throws InterruptedException {while (true) {System.out.println(configTest2.getName() - configTest2.getAge() - configTest2.getEducation());Thread.sleep(1000);}}