Published on

在Springboot中重建RestTemplate Bean

Authors

最近有个需求,用户希望RestTemplate能够绕过ssl证书验证,直接访问目标地址。虽然这并不安全,但是作为开发人员,只能有求必应啊。

需要设计一个开关,是否忽略ssl验证,默认为false。而且配置得动态刷新,也就是说,一旦修改了配置,就要重新生成一个RestTemplate。

实现思路如下:

  1. 增加一个配置rest-template.ignore-ssl-validation,初始值为false
  2. 修改RestTemplate初始化逻辑,根据配置来决定生成的RestTemplate的方式。
  3. 写一个RestTempalteRebuilder类,包含重新生成RestTemplate的逻辑,新建一个RestTemplate bean,从spring中销毁旧的bean,再向spring中注册新的bean
  4. 实现一个ApplicationListener,监听RefreshEvent事件,如果该配置发生变化,则调用RestTempalteRebuilder的重建RestTemplate方法。

遇到的问题:

  1. ApplicationListener 初始化完成后,注解了@ConfigurationProperties的类还没有初始化完,获取的值为null !!!
  2. ApplicationListener 的执行顺序在 RefreshEventListener之前,当监听器触发时,获取不到变化后的值,慢了整整一个八拍!!!

解决办法:

  1. 实现 InitialingBeanafterPropertiesSet() 方法,意思时在依赖的bean全部初始化好之后执行这个方法,所以可以在这里方法里去初始化读取到的配置的值。
  2. 注入 ContextRefresher,当自定义的监听器执行的时候,就去刷新以下缓存,就可以取到变化后的值了。

替换context中的bean

DefaultSingletonBeanRegistry registry = (DefaultSingletonBeanRegistry) applicationContext.getAutowireCapableBeanFactory();
registry.destroySingleton("restTemplate");
registry.registerSingleton("restTemplate", new RestTemplate()); 

首先从ApplicationContext中获取到DefaultSingletonBeanRegistry,使用destroySingleton()来销毁restTemplate bean, 然后使用registerSingleton()将新建好的bean再注册进去,这个registerSingleton() 方法不仅会在 ApplicationContext 中创建 bean,还会自动将其注入到依赖的对象中,完美。