当前位置: 首页 > 知识库问答 >
问题:

多租户环境中的Spring Boot+Thymeleaf+Database TemplateResolver

盛承
2023-03-14
@Bean
@Scope(value = "tenant", proxyMode = ScopedProxyMode.INTERFACES)
public ITemplateResolver databaseTemplateResolver() {

    final DatabaseTemplateResolver resolver = 
        new DatabaseTemplateResolver(systemSettingService, emailTemplateService );

    resolver.setTemplateMode("HTML5");
    resolver.setCacheTTLMs((long) (1000*60*5)); // 5 Minutes
    resolver.setOrder(2);

    return resolver;
}

这很有效,所以看起来。上面指定的作用域是由域确定的多租户环境中为一个租户定义的自定义作用域。但我认为,为了这个问题的目的,这也可能是会话范围。我在这里的想法是,TemplateResolver对于每个范围都是不同的。我们需要它是因为我们正在从租户的数据库中读取模板。

最后,我的症状:似乎第一个房客工作很好。对于任何后续租户,我在试图处理数据库模板时都会遇到异常。

org.thymeleaf.exceptions.NotInitializedException: Template Resolver has not been initialized
    at org.thymeleaf.templateresolver.AbstractTemplateResolver.checkInitialized(AbstractTemplateResolver.java:156)
    at org.thymeleaf.templateresolver.AbstractTemplateResolver.resolveTemplate(AbstractTemplateResolver.java:316)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    ...

我尝试禁用Thymeleaf的Spring Boot自动配置,并手动设置TemplateEngine、ViewResolver、TemplateResolvers等,但也有同样的问题。我还尝试将所有租户设置为作用域,但却遇到了完全不同的混乱和回溯。

/**
 * <p>
 *   Internal method that initializes the Template Engine instance. This method 
 *   is called before the first execution of {@link #process(String, IContext)} 
 *   in order to create all the structures required for a quick execution of 
 *   templates.
 * </p>
 * <p>
 *   THIS METHOD IS INTERNAL AND SHOULD <b>NEVER</b> BE CALLED DIRECTLY.
 * </p>
 * <p>
 *   If a subclass of <tt>TemplateEngine</tt> needs additional steps for
 *   initialization, the {@link #initializeSpecific()} method should
 *   be overridden.
 * </p>
 */
public final synchronized void initialize() {

    if (!isInitialized()) {

        logger.info("[THYMELEAF] INITIALIZING TEMPLATE ENGINE");

        this.configuration.initialize();

        this.templateRepository = new TemplateRepository(this.configuration);

        initializeSpecific();

        this.initialized = true;

        // Log configuration details
        this.configuration.printConfiguration();

        logger.info("[THYMELEAF] TEMPLATE ENGINE INITIALIZED");

    }

}

一旦templateengine被标记为“initialized”,引擎将不会再次初始化,也不会初始化任何配置(根据设计)。因此,我想也许我的想法是正确的,即为新范围注入的新TemplateResolver永远不会初始化。或者更准确地说,它不会被标记为已初始化。

使用所有这些initialized的主要原因之一似乎是将其标记为在完成配置之前不运行,并防止在运行后更改配置。

根据我的发现,并使用上述假设,我更改了TemplateResolver,以便在处理每个模板之前始终检查初始化。这种蛮力方法似乎有效,似乎没有干扰Thymeleaf作者的意图。(当然是根据我的猜测。我真的不知道。我希望。)

    null

共有1个答案

澹台成龙
2023-03-14

通常,TemplateEngine在引擎初始化期间调用TemplateResolver上的Initialize()。但是,在本例中,没有初始化作用域注入的TemplateResolver

相反,我们将创建/注入一个已经“初始化”的TemplateResolver。我们只需将该步骤添加到bean创建中:

@Bean(initMethod="initialize")
@Scope(value = "tenant", proxyMode = ScopedProxyMode.INTERFACES)
public ITemplateResolver databaseTemplateResolver() {

    final DatabaseTemplateResolver resolver = 
        new DatabaseTemplateResolver(systemSettingService, emailTemplateService );

    resolver.setTemplateMode("HTML5");
    resolver.setCacheTTLMs((long) (1000*60*5)); // 5 Minutes
    resolver.setOrder(2);

    return resolver;
}

我唯一担心的是,在这里手动调用initialize可能会有一些不可预见的副作用。我对Thymeleaf还不够了解,不能肯定。不过,到目前为止,还好。

 类似资料:
  • 我最近在工作中遇到了以下架构问题,我不确定这里的最佳做法。 我们为学校提供了一个多租户SAAS应用程序,其体系结构与一个中央主数据库(包含配置和共享数据)以及每个“学校组”的一个特定数据库配合使用。这些群体通常具有地域性,学校合作并为他们的群体取得软件许可证。 这在过去带来了一些问题,因为有时学校会改变群体。我们通过创建一个迁移工具来解决这个问题,该工具从一个数据库中提取学校数据,并将其合并到其他

  • 目前为止,我们已经让用户页面在多租户风格下工作。为使它工作,我们看起来并没有做太多的变化。但请记住,我们正在对一个原来不是多租户的系统作修改。 让我们在 Roles 表应用类似的原则。 再一次,一个租户的用户在不能查看或修改其他租户的角色,每个租户的用户是相互独立工作的。 我们先在 RoleRow.cs 添加 TenantId 属性: namespace MultiTenancy.Administ

  • 本文向大家介绍springboot 多环境配置教程,包括了springboot 多环境配置教程的使用技巧和注意事项,需要的朋友参考一下 在上一课中我们通过idea工具没有做任何配置就构建了一个springboot项目,并且已经成功启动了,但我们都很清楚这些都远远不能达到我们实际项目的需求,比如我们要引入我们自己的redis配置、mysql配置等,应该如何处理呢?在spring mvc中我们都是通过

  • 我在创建可以动态连接到多个数据库的spring boot应用程序时遇到问题,具体取决于用户输入。基本上,应用程序在不同的数据库上运行相同的sql查询。建模我的尝试在此之后,我收到以下错误: -- 配置类: 属性文件: 关于我如何实现这一点有什么想法吗?正如你所知,我对这种多数据库配置还不是非常精通。

  • 保护数据。 清除租户级别的旧数据。 到目前为止,我们的调查结果是,我们可以为每个租户使用单独的Redis实例--这对我们来说不是一个好的解决方案。 我们发现的另一个选项是用“tenant_id:”前缀命名密钥空间。这个选项解决了第一点--数据现在是安全的,但我们还有第二点需要解决。

  • 我有一个由3个节点组成的HDF集群,其中安装了Nifi。我的目标是在Nifi水平上实现多租户(也许不是最好的词)。意思是我想要两件事: null 任何帮助都很感激... 谢谢你的回答