SeamFramework.orgCommunity Documentation

Capitolo 23. Gestione della cache

23.1. Usare la cache in Seam
23.2. Cache dei frammenti di pagina

In quasi tutte le applicazioni gestionali il database è il principale collo di bottiglia e lo strato meno scalabile dell'ambiente di esecuzione. Chi utilizza ambienti PHP/Ruby cercherà di sostenere che le architetture cosiddette "shared nothing" (nessuna condivisione) hanno una buona scalabilità. Benché questo possa essere letteralmente vero, non si conoscono molte applicazioni multi utente che possano essere implementate senza la condivisione di risorse tra diversi nodi di un cluster. In effetti ciò a cui questi sprovveduti stanno pensando è un'architettura con "nessuna condivisione eccetto il database". Ovviamente condividere il database è il principale problema di scalabilità di una applicazione multi utente, perciò affermare che questa architettura è altamente scalabile è assurdo e ci dice molto sul tipo di applicazioni sul cui sviluppo questi signori spendono la maggior parte del tempo.

Quasi tutto ciò che riusciamo a fare per condividere il database meno frequentemente è ben fatto.

E questo richiede una cache (memoria tampone). Un'applicazione Seam ben progettata comprenderà una ricca e stratificata strategia di cache che interessi ogni strato dell'applicazione:

Per ulteriori informazioni sulla cache di secondo livello è necessario fare riferimento alla documentazione della soluzione ORM scelta poiché si tratta di un argomento estremamente complesso. In questo paragrafo verrà affrontato l'uso diretto della cache, tramite il componente cacheProvider o come cache dei frammenti di pagina, tramite il controllo <s:cache>.

Il componente cacheProvider fornito dal framework gestisce una istanza di:

E' possibile mettere con sicurezza nella cache qualsiasi oggetto Java immutabile; esso verrà conservato nella cache e replicato nel cluster (assumendo che la replica sia gestita e abilitata). Se si vuole mantenere degli oggetti mutabili nella cache occorre leggere la documentazione della cache sottostante per scoprire come notificare la cache dei cambiamenti negli oggetti.

Per usare cacheProvider è necessario includere nel progetto i jar dell'implementazione della cache:

Se l'applicazione Seam viene assemblata in un EAR si raccomanda di inserire direttamente nell'EAR la configurazione e i jar della cache.

Sarà inoltre necessario fornire un file di configurazione per JBossCache. Posizionare treecache.xml con un'opportuna configurazione di cache nel classpath (ad esempio nel jar ejb oppure in WEB-INF/classes). JBossCache ha molte impostazioni ostiche e terribili perciò non verranno discusse qui. Per ulteriori informazioni fare riferimento alla documentazione di JBossCache.

E' possibile trovare un treecache.xml di esempio in examples/blog/resources/treecache.xml.

EHCache senza un file di configurazione funzionerà nella sua configurazione di default.

Per modificare il file di configurazione in uso, configurare la cache in components.xml:


<components xmlns="http://jboss.com/products/seam/components"
            xmlns:cache="http://jboss.com/products/seam/cache">
   <cache:jboss-cache-provider configuration="META-INF/cache/treecache.xml" />
</components
>

A questo punto è possibile iniettare la cache in qualsiasi componente Seam:

@Name("chatroomUsers")

@Scope(ScopeType.STATELESS)
public class ChatroomUsers
{
    @In CacheProvider cacheProvider;
    @Unwrap
    public Set<String
> getUsers() throws CacheException   {
        Set<String
> userList = (Set<String
>) cacheProvider.get("chatroom", "userList");
        if (userList==null) {
            userList = new HashSet<String
>();
            cacheProvider.put("chatroom", "userList", userList);
        }
        return userList;
    }
}

Se nell'applicazione si vogliono avere più configurazioni della cache basta usare components.xml per configurare più componenti cacheProvider:


<components xmlns="http://jboss.com/products/seam/components"
            xmlns:cache="http://jboss.com/products/seam/cache">
   <cache:jboss-cache-provider name="myCache" configuration="myown/cache.xml"/>
   <cache:jboss-cache-provider name="myOtherCache" configuration="myother/cache.xml"/>
</components
>

L'uso più interessante della cache in Seam è la tag <s:cache>, che è la soluzione offerta da Seam per il problema di conservare in cache frammenti di pagine JSF. Internamente <s:cache> usa pojoCache, perciò è necessario seguire i passi elencati in precedenza prima di poterla usare (mettere i jar nell'EAR, sistemare le terribili opzioni di configurazione, ecc).

<s:cache> viene usata per conservare quei contenuti generati che cambiano raramente. Ad esempio la pagina di benvenuto del nostro blog mostra le voci del blog più recenti:


<s:cache key="recentEntries-#{blog.id}" region="welcomePageFragments">
   <h:dataTable value="#{blog.recentEntries}" var="blogEntry">
      <h:column>
         <h3
>#{blogEntry.title}</h3>
         <div>
            <s:formattedText value="#{blogEntry.body}"/>
         </div>
      </h:column>
   </h:dataTable>
</s:cache
>

La chiave (key) consente di avere più versioni in cache di ogni frammento di pagina. In questo caso c'è una versione in cache per ogni blog. La regione (region) determina la cache o il nodo region in cui tutte le versioni verranno conservate. Diversi nodi possono avere diverse regole di scadenza (queste sono le cose che si impostano con le summenzionate terribili opzioni di configurazione).

Ovviamente il grosso problema di <s:cache> è che è troppo semplice sapere quando i dati contenuti cambiano (ad esempio quando il blogger pubblica uno nuovo contenuto). Così è necessario eliminare i frammento in cache manualmente:

public void post() {

    ...
    entityManager.persist(blogEntry);
    cacheProvider.remove("welcomePageFragments", "recentEntries-" + blog.getId() );
}

In alternativa, se non è critico che le modifiche siano immediatamente visibili agli utenti, è possibile impostare un tempo di scadenza breve nel nodo della cache.