使用nacos的时候,我们可以把某些配置写在nacos上面,以便于我们修改,那么如何能简单的实现这一功能呢?先看图
看到该图我们发现他是一个map结构,也就是说我们可以在spring初始化完毕之后可以往该map中添加k-v,我们可以通过environment.getProperty("server.port");去获取,这当然没毛病,但是我们使用@Value注解去获取值的时候就不行了,因为spring的bean默认是单例的,这是因为你虽然把值put进去了,这个时候bean已经生成了,bean里面的属性值肯定还是为null。如何解决呢?初始化完所有bean后销毁当前bean,重新生成该bean。
下面上代码
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.stereotype.Component;
@Component
public class MyBeanDefinitionRegistry implements BeanDefinitionRegistryPostProcessor {
private BeanDefinitionRegistry beanDefinitionRegistry;
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
this.beanDefinitionRegistry = beanDefinitionRegistry;
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
configurableListableBeanFactory.registerScope("myRefreshScope", new MyRefreshScope());
}
public BeanDefinitionRegistry getBeanDefinitionRegistry() {
return beanDefinitionRegistry;
}
}
我们定义一个类去实现Scope,由于使用不到其中的方法,所以暂时不用去实现方法
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
import org.springframework.stereotype.Component;
@Component
public class MyRefreshScope implements Scope {
@Override
public Object get(String s, ObjectFactory> objectFactory) {
return null;
}
@Override
public Object remove(String s) {
return null;
}
@Override
public void registerDestructionCallback(String s, Runnable runnable) {
}
@Override
public Object resolveContextualObject(String s) {
return null;
}
@Override
public String getConversationId() {
return null;
}
}
核心代码来了
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.boot.env.OriginTrackedMapPropertySource; import org.springframework.context.ApplicationListener; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.EnvironmentAware; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.core.env.Environment; import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.StandardEnvironment; import org.springframework.stereotype.Component; @Component public class StartReadConfiguration implements EnvironmentAware , ApplicationListener{ private StandardEnvironment environment; private BeanDefinitionRegistry beanDefinitionRegistry; @Autowired private MyBeanDefinitionRegistry myBeanDefinitionRegistry; @Autowired ConfigurableApplicationContext applicationContext; @Override public void setEnvironment(Environment environment) { this.environment = (StandardEnvironment) environment; } @Override public void onApplicationEvent(ContextRefreshedEvent event) { beanDefinitionRegistry = myBeanDefinitionRegistry.getBeanDefinitionRegistry(); init(); } public void init (){ MutablePropertySources propertySources = environment.getPropertySources(); propertySources.forEach(propertySource -> { if (propertySource instanceof OriginTrackedMapPropertySource) { OriginTrackedMapPropertySource originTrackedMapPropertySource = (OriginTrackedMapPropertySource) propertySource; originTrackedMapPropertySource.getSource().put("test.name","ljw1"); // 刷新配置 String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames(); for (String beanDefinitionName : beanDefinitionNames) { BeanDefinition beanDefinition = beanDefinitionRegistry.getBeanDefinition(beanDefinitionName); if ("myRefreshScope".equals(beanDefinition.getScope())) { //销毁当前bean applicationContext.getBeanFactory().destroyBean(beanDefinitionName); //重新获取生成bean,这个 时候属性已经注入进去了 Object bean = applicationContext.getBean(beanDefinitionName); } } } }); } }
测试代码
@RestController
@Scope("myRefreshScope")
public class NacosController {
@Value("${test.name}")
private String name;
@Autowired
Environment environment;
@GetMapping("/")
public String getString(){
//String property = environment.getProperty("server.port");
return "HelloWorld"+name;
}
}
效果如下
那这个时候就会有人说了,你这样不还是把配置在代码中写死了吗。
这只是 一个核心思想,我们可以把数据写在数据库中,通过读取数据库来把信息注入进去
优化点:1、数据库存配置信息 2、通过定时任务及时刷新配置信息 3、增加一个MD5值取进行比较,不用每次都刷新所有。



