title: Spring Boot + Thymeleaf + Database TemplateResolver in a Multi-Tenant environment
body: <p>I'm using Spring Boot and Thymeleaf in a multi-tenant application. I am also using Thymeleaf to process email templates and generate html email. In order to do this, I created a <code>ITemplateResolver</code> that retrieves thymeleaf templates prefixed with "db:" from a database. </p>
  
  <p>Spring Boot auto-configuration picks up any template-resolvers and adds them the the <code>SpringTemplateEngine</code>. So I have a my template resolver set up like this:</p>
  
  <pre><code>@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;
  }
  </code></pre>
  
  <p>As expected, the resolver gets added to the <code>TemplateEngine</code> and any templates with names that start with "db:" are read from the database. This allows us to store specialized email templates that are processed by the Thymeleaf engine to produce the resulting html.</p>
  
  <p>This worked very well, so it seemed. The scope specified above is a custom scope defined for one tenant in a multi-tenant environment determined by the domain. But this might as well be session scoped, I believe, for the purpose of this question. My thought here is that TemplateResolver is different for each scope. We need it to be because we are reading from the tenant's database for the template.</p>
  
  <p>Finally, my symptom: It seems that the <em>first</em> tenant works fine. For any subsequent tenants, I get an exception when attempting to process a database template. </p>
  
  <pre><code>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)
      ...
  </code></pre>
  
  <p>I've tried disabling Spring Boot auto-configuration for Thymeleaf and manually setting up the TemplateEngine, ViewResolver, TemplateResolvers, etc. but have the same problem. I also tried making everything <code>tenant</code> scope but ran into an entirely different mess and back-tracked. </p>
  
  <p>I have a feeling that I'm doing something wrong, or have the wrong idea, of how dependency injection should work in this situation. Or the Thymeleaf engine is implemented in such a way that it is not compatible with the proxy object. I'm leaning towards the latter. Perhaps I need to somehow extend the template engine so that it initializes the resolvers once for each tenant? I believe, maybe, Thymeleaf thinks the resolver is already initialized, then when spring injects a new resolver, it is never initialized by Thymeleaf and hence the exception.</p>
  
  <p>Can anyone give me a push in the right direction?  Thank you.</p>
  
  <p><strong>EDIT:</strong>
  Here is the code for Thymeaf's <code>TemplateEngine</code> method <code>initialize()</code> which is called before any templates are processed. </p>
  
  <pre><code>/**
   * &lt;p&gt;
   *   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.
   * &lt;/p&gt;
   * &lt;p&gt;
   *   THIS METHOD IS INTERNAL AND SHOULD &lt;b&gt;NEVER&lt;/b&gt; BE CALLED DIRECTLY.
   * &lt;/p&gt;
   * &lt;p&gt;
   *   If a subclass of &lt;tt&gt;TemplateEngine&lt;/tt&gt; needs additional steps for
   *   initialization, the {@link #initializeSpecific()} method should
   *   be overridden.
   * &lt;/p&gt;
   */
  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");
  
      }
  
  }
  </code></pre>
  
  <p>In <code>this.configuration.initialize();</code>, various engine configuration is initialized. Among other things, the method initializes ( <strong>calls initialize()</strong> ) on all <code>TemplateResolver</code>s and then marks the engine as <strong>initialized</strong>.</p>
  
  <p>Once the <code>TemplateEngine</code> is marked "initialized," the engine will not be initialized again, nor will any configuration be initialized (by design). So I am thinking that maybe my thought is correct that a new <code>TemplateResolver</code> injected for a new scope will never be initialized. Or, more accurately, it will not be marked as initialized. </p>
  
  <p>It seems that one of the major reasons for the use of all these <code>initialized</code> flags it to keep from running before complete configuration and to prevent changes to configuration once running.</p>
  
  <p>With what I found, and using the above assumptions, I changed my <code>TemplateResolver</code> to always check for initialization before every template is processed. This brute force method appears to work and does not seem to interfere with the intent of the Thymeleaf authors. (Based on my guess, of course. I really do not know. I am hoping.)</p>
  
  <p><strong>VERSIONS:</strong></p>
  
  <ul>
  <li>Thymeleaf 2.1.4.RELEASE</li>
  <li>Spring 4.1.6.RELEASE</li>
  <li>Spring Boot 1.2.5.RELEASE</li>
  </ul>