技巧!Spring Boot生产环境重新初始化Bean

开发 前端
为了演示我们将创建一个bean,该Bean将从配置文件中读取配置属性。如果文件中的属性发生变化,则对该Bean进行重新初始化以便得到最新的数据。

1. 简介

在本篇文章中,我将介绍在运行时重新初始化单例 Spring Bean 的方法。默认情况下,具有单例作用域的 Spring Bean 不会在应用程序生命周期中重新初始化。不过,有时可能需要重新创建 Bean,例如在更新属性时。我将介绍几种实现此功能的方法。

2. 实战案例

为了演示我们将创建一个bean,该Bean将从配置文件中读取配置属性。如果文件中的属性发生变化,则对该Bean进行重新初始化以便得到最新的数据。

2.1 单例Bean定义

@Component
public class ConfigManager {


  private static final Logger logger = LoggerFactory.getLogger(ConfigManager.class) ;


  private Map<String, Object> config = new HashMap<>() ;
  // 配置的是具体值是绝对路径
  private final String filePath ;
  public ConfigManager(@Value("${pack.app.filePath}") String filePath) {
    this.filePath = filePath ;
    // 创建该bean对象时,加载配置文件信息
    initConfig() ;
  }
  private void initConfig() {
    Properties properties = new Properties() ;
    try {
      properties.load(Files.newInputStream(Paths.get(filePath))) ;
    } catch (IOException e) {
      logger.error("错误的加载配置文件, {}", e) ;
    }
    for (Map.Entry<Object, Object> entry : properties.entrySet()) {
      config.put(String.valueOf(entry.getKey()), entry.getValue());
    }
  }
  public Object getConfig(String key) {
    return config.get(key) ;
  }
}

接下来,在classpath下新建config.properties配置文件,配置内容如下:

pack:
  app:
    filePath: d:/pack/config.properties

下面我们可以定义一个Controller该测试当前的配置是否有问题。

@RestController
@RequestMapping("/config")
public class ConfigController {


  @Autowired
  private ConfigManager configManager;


  @GetMapping("/{key}")
  public Object get(@PathVariable String key) {
    return configManager.getConfig(key);
  }
}

默认配置文件内容

title=xxxooo1

访问接口

图片图片

目前,上面的接口不管配置如何修改,在不重启服务的情况下都无法得到最新的值;接下来我将通过几种方式来演示如何去刷新最新的配置。

2.2 通过公共方法刷新

如果我们想要重新加载属性而不是重新创建对象本身,我们可以简单地创建一个公共方法来再次初始化。在我们的ConfigManager中,让我们添加一个调用reloadConfig()方法的方法:

public void reloadConfig() {
  initConfig() ;
}

然后,当我们要重新加载属性时,就可以调用该方法。接着在Controller中定义另一个接口,该接口调用 reloadConfig()方法:

@GetMapping("/reloadConfig")
public void reloadConfig() {
  configManager.reloadConfig() ;
}

通过测试上面的代码,你将得到最新的配置。此种方法也是最容易想到的办法。

2.3 使用@Lazy注解

我们可以使用@Lazy注解添加到注入的ConfigManager对象的地方,如下示例:

@Resource
@Lazy
private ConfigManager configManager;
@Value("${pack.app.filePath}")
private String filePath ;
@GetMapping("/reinitializeBean")
public void reinitializeBean() {
  DefaultSingletonBeanRegistry registry = (DefaultSingletonBeanRegistry) context.getAutowireCapableBeanFactory() ;
  // 销毁bean;销毁后当再次使用该bean时容器会再次执行整个创建过程
  registry.destroySingleton("configManager") ;
}

当配置发生变化后,先调用上面的/reinitializeBean接口,这会先把单例池中的实例删除,当再次调用/title接口时就会重新创建对象了。

2.4 通过容器获取Bean

我们可以将对应的bean销毁,然后在使用的时候再次从容器中获取,这时候由于已经将该单例bean销毁,单例池中已经没有了,所以会重新创建。

@Resource
private ApplicationContext context ;
@Value("${pack.app.filePath}")
private String filePath ;
@GetMapping("/destroyBean")
public void destroyBean() {
  DefaultSingletonBeanRegistry registry = (DefaultSingletonBeanRegistry) applicationContext.getAutowireCapableBeanFactory() ;
  registry.destroySingleton("configManager") ;
}

接下来修改使用获取数据的接口

@GetMapping("/{key}")
public Object get(@PathVariable String key) {
  ConfigManager cm = context.getBean(ConfigManager.class) ;
  return cm.getConfig(key) ;
}

如果配置文件修改后,我们先调用/destroyBean接口,这样当我们调用/title接口时,将会获取到最新的配置。

责任编辑:武晓燕 来源: Spring全家桶实战案例源码
相关推荐

2024-10-18 11:32:15

2011-03-31 16:46:10

LinuxMySQL

2010-01-05 15:35:21

.NET Framew

2009-08-12 17:43:54

双括弧Java语法技巧

2022-05-10 10:06:03

Kafka

2023-05-03 23:48:24

Spring容器初始化

2024-07-31 11:26:05

反射BeanXML

2010-02-24 15:41:19

Linux Light

2023-11-12 23:08:17

C++初始化

2023-12-01 10:20:00

SpringBean参数机制

2010-02-07 14:50:46

Ubuntu配置文件

2010-03-11 19:25:35

Python环境

2010-01-22 13:16:05

VB.NET初始化数组

2023-05-08 15:55:16

MySQL数据库

2023-04-08 14:22:16

Spring初始化对象

2021-07-12 12:20:08

Spring初始化方案

2011-06-17 15:29:44

C#对象初始化器集合初始化器

2009-11-11 15:29:15

ADO初始化

2019-11-04 13:50:36

Java数组编程语言

2009-09-08 09:48:34

LINQ初始化数组
点赞
收藏

51CTO技术栈公众号