【问题标题】:Spring Application Context Refresh in webapplicationWeb应用程序中的Spring Applicationcontext刷新
【发布时间】:2015-08-21 18:51:49
【问题描述】:

在我的应用程序中,在服务器启动期间,spring bean DAO 类从数据库中读取值并使用 spring jdbc 模板存储在哈希图中。

我需要在运行时重新加载一组特定的 bean,而无需重新启动应用服务器。

下面是我的代码 sn-p。如果需要,我可以发布更多内容

private void setMessageDetails() {
messageContentDetails= namedParameterJdbcTemplate.queryForObject(messageContentSql,nameParamMap, new MessageContentRowMapper());
}

MessageContentRowMapper.java maps the resultset values to valuesMap below

public class MessageContentDetails {
private Map<String, Map<String, String>> valuesMap= new HashMap<String, Map<String, String>>();
 ..setters/getters..
} 

现在,如果任何 DB 值发生变化,我需要重新初始化 MessageContentDetails.java 并使用新值更新 hashmap,并且还需要在应用程序启动期间之前自动装配/注入的地方再次自动装配此类的引用。

我的问题是

  1. 我能否使用 applicationContext.refresh() 方法刷新一个或一组 Spring bean。
  2. 有没有更好的方法来重新加载具有一些需要在运行时重新加载的静态值的 spring bean?
  3. 使用此方法可能对线程产生什么影响。我的应用程序分布在 3 个具有多个 jvm 的不同数据中心。

任何指向我上述问题的链接都会非常有帮助。

我使用的是 JAVA 1.6 WebSphere Spring 3.1.0 版本,MessageContentDetails bean 是在 spring xml 中配置的 spring bean,没有注释。

【问题讨论】:

  • 可能为时已晚,但是:en.wikipedia.org/wiki/OSGi
  • 仅供参考,我不相信您可以刷新特定的 bean 集,它应该是全部或没有。
  • @John 可以说我将我的 spring bean 定义拆分为单独的 xml,我可以只重新加载可能包含所有需要重新加载的 bean 的特定 xml 吗?我的意思是这能解决我的目的吗
  • @John 使用 OSGI 为时已晚。我将如何研究它。我想知道多线程的影响及其在重新加载 spring bean 时的影响。
  • 如何知道这些数据库更改何时发生,这是手动步骤吗?

标签: java spring spring-mvc


【解决方案1】:

我不确定这是否可以通过开箱即用的 Spring 实现,通过一些技巧和多种上下文可能是可能的。 Spring 默认会在refresh 的某些上下文中销毁所有单例。

但是,考虑到您的情况,在没有 Spring 参与的情况下实现此要求并不难。

你需要做的是在运行时更新一个静态地图,就是这样:)

一般解决方案:

1) 引入 Web 服务,让您提供新的更新值,

2) 制作依赖于可更新 bean Observers 的 bean 并提供块释放机制,

3)

  • 通过反射或多态编写通用映射,让您可以更新任何 bean 的静态值

  • 编写 Web 服务负载和目标 bean 状态之间的特定映射。

让我们从 1 开始:

@Controller
public class BeanUpdateController {

@Autowired
private UpdateService updateService;


@RequestMapping(value = "/updateState", method = RequestMethod.POST)
@ResponseBody
public UpdateResponse handleUpdateRequest(@Valid @RequestBody someXMLYouDefine updateRequest) {

    return updateService.execute(voucher);
}

请注意,您也可以使用 RequestMethod.GET 和 URL 参数。

然而,想法是您以某种可解析的格式传输您希望更新的Bean 的名称、字段名称和适当的值。

让我们转到 3:

@Component
public class BeanLocator implements ApplicationContextAware {

private static ApplicationContext context;

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    context = applicationContext;   
}

public Object getBean(String beanName)  {

    return context.getBean(beanName);

}

protected ApplicationContext getContext() {

    return context;
}

此服务可让您按名称查找 Bean,该名称包含在 Web 服务的负载中。

获得 bean 后,您有几个选择:

1) 让“可更新”Beans 实现一些接口,例如Updatable,并传递它们将自行更新的字段名称和值。

2) 使用反射,可能是这样的:

对于负载中的每个字段名称:

Field field = acquiredBean.getClass().getDeclaredField("fieldNameFromThePayload");

如果是原语,你可以这样做:

field.setAccessible(true);
field.set(acquiredBean,"valueFromPayload")

如果它是 Collection 或 Map 并且如果您使用 XSD 表示此结构,您可以直接将列表从生成的类映射到目标 bean。当然你也可以手动迭代。

实现选项 3 的最简单但最不灵活的方法是在 GET 请求中简单地将值作为 URL 参数传递,并让服务获取对 Bean 映射的引用,然后更新该映射。

现在回到第二步,如果不是业务关键,您可以跳过。

每个可能依赖于“可更新”bean 的 bean 都应该实现 Observer 接口。当更新请求到来时,他们通过策略模式切换实现,以便在更新过程中将所有传入请求排队。一旦 bean 更新,它应该发送确认。这将触发另一个侦听服务通知,该通知将取消阻止排队的请求并继续处理。

Web 服务更新请求应广播到所有具有可更新 bean 的节点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-17
    • 2015-04-16
    • 2015-03-31
    • 1970-01-01
    • 2019-06-22
    • 2018-02-17
    相关资源
    最近更新 更多